Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Progressing on validation of special tags using a JSON specification of properties #226

Merged
merged 3 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bids/types/json.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ export class BidsSidecarKey {
file: this.sidecar.deref()?.file?.relativePath,
})
}
const [parsedString, parsingIssues] = parseHedString(string, hedSchemas)
const [parsedString, parsingIssues] = parseHedString(string, hedSchemas, false)
this.parsedCategoryMap.set(value, parsedString)
issues.push(...Object.values(parsingIssues).flat())
}
Expand Down
2 changes: 2 additions & 0 deletions bids/validator/sidecarValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@ export class BidsHedSidecarValidator {

for (const [sidecarKey, hedData] of this.sidecar.parsedHedData) {
if (hedData instanceof ParsedHedString) {
// Value options have HED as string
issues.push(...this._validateString(sidecarKey, hedData, valueOptions))
} else if (hedData instanceof Map) {
// Categorical options have HED as a Map
for (const valueString of hedData.values()) {
issues.push(...this._validateString(sidecarKey, valueString, categoricalOptions))
}
Expand Down
33 changes: 29 additions & 4 deletions common/issues/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ export default {
level: 'error',
message: stringTemplate`Definitions were found in string "${'string'}" in a context where definitions are not allowed.`,
},
illegalDefinitionInExclusiveContext: {
hedCode: 'DEFINITION_INVALID',
illegalInExclusiveContext: {
hedCode: 'TAG_INVALID',
level: 'error',
message: stringTemplate`Mixed definition and non-definition tags or tag groups were found in string "${'string'}" in a context where only one type is allowed.`,
message: stringTemplate`"${'tag'}" can only appear in groups of the same type but "${'string'}" has other groups or tags.`,
},
inactiveOnset: {
hedCode: 'TEMPORAL_TAG_ERROR',
Expand Down Expand Up @@ -184,21 +184,41 @@ export default {
level: 'error',
message: stringTemplate`HED event string "${'string'}" has onset/offset tags with duplicated definition "${'definition'}".`,
},
missingTagGroup: {
hedCode: 'TAG_GROUP_ERROR',
level: 'error',
message: stringTemplate`Tag "${'tag'}" must appear in a tag group.`,
},
invalidTopLevelTagGroupTag: {
hedCode: 'TAG_GROUP_ERROR',
level: 'error',
message: stringTemplate`Tag "${'tag'}" is only allowed inside of a top-level tag group.`,
message: stringTemplate`Tag "${'tag'}" is only allowed inside of a top-level tag group, but is not at top level in "${'string'}".`,
},
invalidGroupTopTags: {
hedCode: 'TAG_GROUP_ERROR',
level: 'error',
message: stringTemplate`Tags "${'tags'}" cannot be at the same level in a group.`,
},
multipleTopLevelTagGroupTags: {
hedCode: 'TAG_GROUP_ERROR',
level: 'error',
message: stringTemplate`Tag "${'tag'}" found in top-level tag group where "${'otherTag'}" was already defined.`,
},
invalidNumberOfSubgroups: {
hedCode: 'TAG_GROUP_ERROR',
level: 'error',
message: stringTemplate`The tags "${'tags'} in "${'string'} require groups that do not agree or are not present in their group .`,
},
invalidTopLevelTag: {
hedCode: 'TAG_GROUP_ERROR',
level: 'error',
message: stringTemplate`Tag "${'tag'}" is only allowed inside of a tag group.`,
},
invalidGroupTag: {
hedCode: 'TAG_GROUP_ERROR',
level: 'error',
message: stringTemplate`Tag "${'tag'}" should be in a group in "${'string'}" but is not.`,
},
// Tag conversion issues
invalidParentNode: {
hedCode: 'TAG_EXTENSION_INVALID',
Expand Down Expand Up @@ -256,6 +276,11 @@ export default {
level: 'error',
message: stringTemplate`Curly brace expression "${'column'}" found in the HED column of a TSV file.`,
},
curlyBracesNotAllowed: {
hedCode: 'CHARACTER_INVALID',
level: 'error',
message: stringTemplate`Curly brace expression not allowed in "${'string'}".`,
},
recursiveCurlyBraces: {
hedCode: 'SIDECAR_BRACES_INVALID',
level: 'error',
Expand Down
67 changes: 37 additions & 30 deletions data/json/specialTags.json
Original file line number Diff line number Diff line change
@@ -1,138 +1,145 @@
{
"Def": {
"allowExtension": false,
"allowValue": true,
"allowTwoLevelValue": true,
"requireValue": true,
"exclusive": false,
"tagGroup": false,
"topLevelTagGroup": false,
"maxNumberSubgroups": -1,
"minNumberSubgroups": -1,
"ERROR_CODE": "DEF_INVALID",
"noSpliceInGroup": false,
"forbiddenSubgroupTags": [],
"defTagRequired": false,
"otherAllowedTags": []
"otherAllowedTags": null
},
"Def-expand": {
"allowExtension": false,
"allowValue": true,
"allowTwoLevelValue": true,
"requireValue": true,
"exclusive": false,
"tagGroup": true,
"topLevelTagGroup": false,
"maxNumberSubgroups": 1,
"minNumberSubgroups": 0,
"ERROR_CODE": "DEF_EXPAND_INVALID",
"forbiddenSubgroupTags": [
"Def",
"Def-expand",
"Definition",
"Delay",
"Duration",
"Event-context",
"Inset",
"Offset",
"Onset"
],
"noSpliceInGroup": true,
"forbiddenSubgroupTags": ["Def", "Def-expand"],
"defTagRequired": false,
"otherAllowedTags": []
},
"Definition": {
"allowExtension": false,
"allowValue": true,
"allowTwoLevelValue": true,
"requireValue": true,
"exclusive": true,
"tagGroup": true,
"topLevelTagGroup": true,
"maxNumberSubgroups": 1,
"minNumberSubgroups": 0,
"ERROR_CODE": "DEFINITION_INVALID",
"forbiddenSubgroupTags": [
"Def",
"Def-expand",
"Definition",
"Delay",
"Duration",
"Event-context",
"Inset",
"Offset",
"Onset"
],
"noSpliceInGroup": true,
"forbiddenSubgroupTags": ["Def", "Def-expand"],
"defTagRequired": false,
"otherAllowedTags": []
},
"Delay": {
"allowExtension": false,
"allowValue": true,
"allowTwoLevelValue": false,
"requireValue": true,
"exclusive": false,
"tagGroup": true,
"topLevelTagGroup": true,
"maxNumberSubgroups": 1,
"minNumberSubgroups": 1,
"ERROR_CODE": "TEMPORAL_TAG_ERROR",
"forbiddenSubgroupTags": ["Definition", "Delay", "Duration", "Event-context", "Inset", "Offset", "Onset"],
"noSpliceInGroup": false,
"forbiddenSubgroupTags": [],
"defTagRequired": false,
"otherAllowedTags": ["Duration"]
},
"Duration": {
"allowExtension": false,
"allowValue": true,
"allowTwoLevelValue": false,
"requireValue": true,
"exclusive": false,
"tagGroup": true,
"topLevelTagGroup": true,
"maxNumberSubgroups": 1,
"minNumberSubgroups": 1,
"ERROR_CODE": "TEMPORAL_TAG_ERROR",
"forbiddenSubgroupTags": ["Definition", "Delay", "Duration", "Event-context", "Inset", "Offset", "Onset"],
"noSpliceInGroup": false,
"forbiddenSubgroupTags": [],
"defTagRequired": false,
"otherAllowedTags": ["Delay"]
},
"Event-context": {
"allowExtension": false,
"allowValue": false,
"allowTwoLevelValue": false,
"requireValue": false,
"exclusive": false,
"tagGroup": true,
"topLevelTagGroup": true,
"maxNumberSubgroups": null,
"minNumberSubgroups": 0,
"ERROR_CODE": "TAG_GROUP_ERROR",
"forbiddenSubgroupTags": ["Event-context", "Definition", "Onset", "Inset", "Offset", "Delay", "Duration"],
"noSpliceInGroup": true,
"forbiddenSubgroupTags": [],
"defTagRequired": false,
"otherAllowedTags": []
},
"Inset": {
"allowExtension": false,
"allowValue": false,
"allowTwoLevelValue": false,
"requireValue": false,
"exclusive": false,
"tagGroup": true,
"topLevelTagGroup": true,
"maxNumberSubgroups": 1,
"minNumberSubgroups": 0,
"ERROR_CODE": "TEMPORAL_TAG_ERROR",
"forbiddenSubgroupTags": ["Definition", "Delay", "Duration", "Event-context", "Inset", "Offset", "Onset"],
"noSpliceInGroup": false,
"forbiddenSubgroupTags": [],
"defTagRequired": true,
"otherAllowedTags": []
},
"Offset": {
"allowExtension": false,
"allowValue": false,
"allowTwoLevelValue": false,
"requireValue": false,
"exclusive": false,
"tagGroup": true,
"topLevelTagGroup": true,
"maxNumberSubgroups": 0,
"maxNumberSubgroups": 1,
"minNumberSubgroups": 0,
"ERROR_CODE": "TEMPORAL_TAG_ERROR",
"noSpliceInGroup": false,
"forbiddenSubgroupTags": [],
"defTagRequired": true,
"otherAllowedTags": []
"otheAllowedTags": ["Def"]
},
"Onset": {
"allowExtension": false,
"allowValue": false,
"allowTwoLevelValue": false,
"requireValue": false,
"exclusive": false,
"tagGroup": true,
"topLevelTagGroup": true,
"maxNumberSubgroups": 1,
"minNumberSubgroups": 0,
"ERROR_CODE": "TEMPORAL_TAG_ERROR",
"forbiddenSubgroupTags": ["Definition", "Delay", "Duration", "Event-context", "Inset", "Offset", "Onset"],
"noSpliceInGroup": false,
"forbiddenSubgroupTags": [],
"defTagRequired": true,
"otherAllowedTags": []
}
Expand Down
36 changes: 27 additions & 9 deletions parser/parsedHedGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,25 @@ import ParsedHedColumnSplice from './parsedHedColumnSplice'
* A parsed HED tag group.
*/
export default class ParsedHedGroup extends ParsedHedSubstring {
static SPECIAL_SHORT_TAGS = new Set(['Definition', 'Def', 'Def-expand', 'Onset', 'Offset', 'Inset'])

/**
* The parsed HED tags in the HED tag group.
static SPECIAL_SHORT_TAGS = new Set([
'Definition',
'Def',
'Def-expand',
'Onset',
'Offset',
'Inset',
'Delay',
'Duration',
'Event-context',
])

/**
* The parsed HED tags or parsedHedGroups or parsedColumnSplices in the HED tag group at the top level
* @type {ParsedHedSubstring[]}
*/
tags
/**
* Any HED tags with special handling.
* Any HED tags with special handling. This only covers top-level tags in the group
* @type {Map<string, ParsedHedTag[]>}
*/
specialTags
Expand All @@ -35,7 +45,7 @@ export default class ParsedHedGroup extends ParsedHedSubstring {

/**
* Constructor.
* @param {ParsedHedSubstring[]} parsedHedTags The parsed HED tags in the HED tag group.
* @param {ParsedHedSubstring[]} parsedHedTags The parsed HED tags, groups or column splices in the HED tag group.
* @param {Schemas} hedSchemas The collection of HED schemas.
* @param {string} hedString The original HED string.
* @param {number[]} originalBounds The bounds of the HED tag in the original HED string.
Expand Down Expand Up @@ -69,9 +79,6 @@ export default class ParsedHedGroup extends ParsedHedSubstring {
* @returns {null|ParsedHedTag[]} The tag(s) matching the short tag.
*/
static findGroupTags(group, hedSchemas, shortTag) {
if (!hedSchemas.isHed3) {
return undefined
}
const tags = group.tags.filter((tag) => {
if (!(tag instanceof ParsedHedTag)) {
return false
Expand Down Expand Up @@ -224,6 +231,17 @@ export default class ParsedHedGroup extends ParsedHedSubstring {
})
}

/**
* The trailing portion of {@link canonicalTag}.
*
* @returns {string} The "name" portion of the canonical tag.
*/
get allColumnSplices() {
return this._memoize('allColumnSplices', () => {
return Array.from(this.columnSpliceIterator())
})
}

/**
* Determine the name of this group's definition.
*/
Expand Down
Loading
Loading