diff --git a/.codespellrc b/.codespellrc index b8dcffec..1fbd9fa6 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,3 +1,3 @@ [codespell] -skip = datasets,.git,*.pdf,*.svg,deprecated,*.xml,*.mediawiki,*.omn,datasets -ignore-words-list = covert,hed,recuse,afterAll,hertzs +skip = datasets,.git,*.pdf,*.svg,deprecated,*.xml,*.mediawiki,*.omn,datasets, docs/html/fonts, docs/html/scripts +ignore-words-list = covert,hed,recuse,afterAll,hertzs,isnt diff --git a/docs/html/BidsFile.html b/docs/html/BidsFile.html new file mode 100644 index 00000000..b9a5ce8a --- /dev/null +++ b/docs/html/BidsFile.html @@ -0,0 +1,413 @@ + + + + + JSDoc: Class: BidsFile + + + + + + + + + +
+

Class: BidsFile

+ +
+
+

+ BidsFile(name, file, validatorClass) +

+ +
A BIDS file.
+
+ +
+
+

Constructor

+ +

+ new BidsFile(name, file, validatorClass) +

+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + string + The name of the file -- used for messages.
file + object + The representation of the file for error messages.
validatorClass
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
BidsFile
+
+
+ +

Members

+ +

+ file :object +

+ +
+ The file object representing this file data. This is used to generate + BidsIssue objects. +
+ +
Type:
+
    +
  • + object +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ name :string +

+ +
The name of this file.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ validatorClass +

+ +
The validator class used to validate this file.
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ hasHedData() → {boolean} +

+ +
Determine whether this file has any HED data.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- True if this file has HED data.
+ +
+
Type
+
+ boolean +
+
+ +

+ validate(schemas) → {Array.<BidsIssue>} +

+ +
Validate this validator's tsv file.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemas + Schemas + The HED schemas used to validate this file.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- Any issues found during validation of this TSV file.
+ +
+
Type
+
+ Array.<BidsIssue> +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsHedIssue_BidsHedIssue.html b/docs/html/BidsHedIssue_BidsHedIssue.html new file mode 100644 index 00000000..cf56f4fc --- /dev/null +++ b/docs/html/BidsHedIssue_BidsHedIssue.html @@ -0,0 +1,235 @@ + + + + + JSDoc: Class: BidsHedIssue + + + + + + + + + +
+

Class: BidsHedIssue

+ +
+
+

+ BidsHedIssue(hedIssue, file) +

+
+ +
+
+

+ new BidsHedIssue(hedIssue, file) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hedIssue + Issue + The HED issue object to be wrapped.
file + Object + The file this error occurred in.
+ +
+
Source:
+
+ +
+
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsHedSidecarValidator.html b/docs/html/BidsHedSidecarValidator.html new file mode 100644 index 00000000..188994ea --- /dev/null +++ b/docs/html/BidsHedSidecarValidator.html @@ -0,0 +1,344 @@ + + + + + JSDoc: Class: BidsHedSidecarValidator + + + + + + + + + +
+

Class: BidsHedSidecarValidator

+ +
+
+

+ BidsHedSidecarValidator(sidecar, hedSchemas) +

+ +
Validator for HED data in BIDS JSON sidecars.
+
+ +
+
+

Constructor

+ +

+ new BidsHedSidecarValidator(sidecar, hedSchemas) +

+ +
Constructor for the BidsHedSidecarValidator.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sidecar + BidsSidecar + The BIDS bidsFile being validated.
hedSchemas + Schemas + The schemas used for the sidecar validation.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
BidsHedSidecarValidator
+
+
+ +

Methods

+ +

+ _validateCurlyBraces() → {Array.<BidsIssue>} +

+ +
+ Validate this bidsFile's curly braces -- checking recursion and missing columns. +
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
All issues found.
+ +
+
Type
+
+ Array.<BidsIssue> +
+
+ +

+ _validateStrings() → {Array.<BidsIssue>} +

+ +
Validate this bidsFile's HED strings.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
All issues found.
+ +
+
Type
+
+ Array.<BidsIssue> +
+
+ +

+ validate() → {Array.<BidsIssue>} +

+ +
+ Validate a BIDS JSON bidsFile file. This method returns the complete issue list for convenience. +
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- Any issues found during validation of this bidsFile file.
+ +
+
Type
+
+ Array.<BidsIssue> +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsHedTsvParser.html b/docs/html/BidsHedTsvParser.html new file mode 100644 index 00000000..7c1751f4 --- /dev/null +++ b/docs/html/BidsHedTsvParser.html @@ -0,0 +1,438 @@ + + + + + JSDoc: Class: BidsHedTsvParser + + + + + + + + + +
+

Class: BidsHedTsvParser

+ +
+
+

+ BidsHedTsvParser(tsvFile, hedSchemas) +

+ +
Class that performs basic parsing and splicing.
+
+ +
+
+

Constructor

+ +

+ new BidsHedTsvParser(tsvFile, hedSchemas) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tsvFile + BidsTsvFile + The BIDS TSV file being parsed.
hedSchemas + Schemas + The HED schema collection being parsed against.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
BidsHedTsvParser
+
+
+ +

Members

+ +

+ hedSchemas + :Schemas +

+ +
The HED schema collection being parsed against.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ tsvFile + :BidsTsvFile +

+ +
The BIDS TSV file being parsed.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ _parseElementStrings(elements) → {Array.<BidsHedIssue>} +

+ +
Parse element HED strings.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
elements + Array.<BidsTsvElement> + The objects representing tsv rows with their parsed HEd strings.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- The issues resulting in creating the parsed HED strings.
+ +
+
Type
+
+ Array.<BidsHedIssue> +
+
+ +

+ parse() → {Array} +

+ +
Combine the BIDS bidsFile HED data into a BIDS TSV file's HED data.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- Returns a two-element array [BidsTsvElement[], BidsHedIssue[]].
+ +
+
Type
+
+ Array +
+
+ +

+ spliceValues(columnMap) +

+ +
Update the map to splice-in the values for columns that have splices.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
columnMap + Map + + Map of column name to HED string for a row. Note: Updates the map in place. +
+ +
+
Source:
+
+ +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsHedTsvValidator.html b/docs/html/BidsHedTsvValidator.html new file mode 100644 index 00000000..2f2210e9 --- /dev/null +++ b/docs/html/BidsHedTsvValidator.html @@ -0,0 +1,424 @@ + + + + + JSDoc: Class: BidsHedTsvValidator + + + + + + + + + +
+

Class: BidsHedTsvValidator

+ +
+
+

+ BidsHedTsvValidator(tsvFile, hedSchemas) +

+ +
Validator for HED data in BIDS TSV files.
+
+ +
+
+

Constructor

+ +

+ new BidsHedTsvValidator(tsvFile, hedSchemas) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tsvFile + BidsTsvFile + The BIDS TSV file being validated.
hedSchemas + Schemas + The HED schemas used to validate the tsv file.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
BidsHedTsvValidator
+
+
+ +

Members

+ +

+ reserved + :ReservedChecker +

+ +
The BIDS TSV file being validated.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ _checkNoTime(elements) → {Array.<BidsHedIssue>} +

+ +
Verify that this non-temporal file does not contain any temporal tags.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
elements + Array.<BidsTsvElement> + The elements representing a tsv file (with HED string parsed).
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- Issues from checking non-temporal files for temporal tags.
+ +
+
Type
+
+ Array.<BidsHedIssue> +
+
+ +

+ validate() → {Array.<BidsIssue>} +

+ +
+ Validate a BIDS TSV file. This method returns the complete issue list for convenience. +
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- Any issues found during validation of this TSV file.
+ +
+
Type
+
+ Array.<BidsIssue> +
+
+ +

+ validateDataset(elements) → {Array.<BidsHedIssue>} +

+ +
+ Validate the HED data in a combined event TSV file/bidsFile BIDS data collection. +
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
elements + Array.<BidsTsvElement> + The element objects, which include the strings and row information.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- The errors resulting from final validation, including dataset-level checks.
+ +
+
Type
+
+ Array.<BidsHedIssue> +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsHedValidator.html b/docs/html/BidsHedValidator.html new file mode 100644 index 00000000..3073ef63 --- /dev/null +++ b/docs/html/BidsHedValidator.html @@ -0,0 +1,384 @@ + + + + + JSDoc: Class: BidsHedValidator + + + + + + + + + +
+

Class: BidsHedValidator

+ +
+
+

+ BidsHedValidator(dataset, schemaDefinition) +

+ +
A validator for HED content in a BIDS dataset.
+
+ +
+
+

Constructor

+ +

+ new BidsHedValidator(dataset, schemaDefinition) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
dataset + BidsDataset + The BIDS dataset being validated.
schemaDefinition + SchemasSpec + The version spec for the schema to be loaded.
+ +
+
Source:
+
+ +
+
+
+ +

Members

+ +

+ dataset + :BidsDataset +

+ +
The BIDS dataset being validated.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ hedSchemas + :Schemas +

+ +
The HED schema collection being validated against.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ issues + :Array.<BidsIssue> +

+ +
The issues found during validation.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ schemaDefinition + :SchemasSpec +

+ +
The schema specification override.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ validateFullDataset() → {Array.<BidsIssue>} +

+ +
Validate a full BIDS dataset using a HED schema collection.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
Any issues found.
+ +
+
Type
+
+ Array.<BidsIssue> +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsJsonFile.html b/docs/html/BidsJsonFile.html new file mode 100644 index 00000000..213db186 --- /dev/null +++ b/docs/html/BidsJsonFile.html @@ -0,0 +1,235 @@ + + + + + JSDoc: Class: BidsJsonFile + + + + + + + + + +
+

Class: BidsJsonFile

+ +
+
+

+ BidsJsonFile() +

+ +
A BIDS JSON file.
+
+ + +
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsSidecarKey_BidsSidecarKey.html b/docs/html/BidsSidecarKey_BidsSidecarKey.html new file mode 100644 index 00000000..0f0d0912 --- /dev/null +++ b/docs/html/BidsSidecarKey_BidsSidecarKey.html @@ -0,0 +1,248 @@ + + + + + JSDoc: Class: BidsSidecarKey + + + + + + + + + +
+

Class: BidsSidecarKey

+ +
+
+

+ BidsSidecarKey(key, data, sidecar) +

+
+ +
+
+

+ new BidsSidecarKey(key, data, sidecar) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
key + string + The name of this key.
data + string + | + + Object.<string, string> + The data for this key.
sidecar + BidsSidecar + The parent bidsFile.
+ +
+
Source:
+
+ +
+
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsSidecar_BidsSidecar.html b/docs/html/BidsSidecar_BidsSidecar.html new file mode 100644 index 00000000..e8fbd0f7 --- /dev/null +++ b/docs/html/BidsSidecar_BidsSidecar.html @@ -0,0 +1,266 @@ + + + + + JSDoc: Class: BidsSidecar + + + + + + + + + +
+

Class: BidsSidecar

+ +
+
+

+ BidsSidecar(name, sidecarData, file, defManager) +

+
+ +
+
+

+ new BidsSidecar(name, sidecarData, file, defManager) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
name + string + The name of the bidsFile file.
sidecarData + Object + The raw JSON data.
file + Object + The file object representing this file.
defManager + DefinitionManager + nullThe external definitions to use
+ +
+
Source:
+
+ +
+
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsTsvElement_BidsTsvElement.html b/docs/html/BidsTsvElement_BidsTsvElement.html new file mode 100644 index 00000000..51c2e1b0 --- /dev/null +++ b/docs/html/BidsTsvElement_BidsTsvElement.html @@ -0,0 +1,258 @@ + + + + + JSDoc: Class: BidsTsvElement + + + + + + + + + +
+

Class: BidsTsvElement

+ +
+
+

+ BidsTsvElement(hedString, tsvFile, onset, tsvLine) +

+
+ +
+
+

+ new BidsTsvElement(hedString, tsvFile, onset, tsvLine) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hedString + string + The HED string representing this row
tsvFile + BidsTsvFile + The file this row belongs to.
onset + number + The onset for this element or undefined if none
tsvLine + string + + The line number(s) (string) corresponding to the lines in tsvFile this line is located at. +
+ +
+
Source:
+
+ +
+
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsTsvFile.html b/docs/html/BidsTsvFile.html new file mode 100644 index 00000000..66f2cb4d --- /dev/null +++ b/docs/html/BidsTsvFile.html @@ -0,0 +1,455 @@ + + + + + JSDoc: Class: BidsTsvFile + + + + + + + + + +
+

Class: BidsTsvFile

+ +
+
+

+ BidsTsvFile(name, {{headers:, file, potentialSidecars, mergedDictionary, defManager) +

+ +
A BIDS TSV file.
+
+ +
+
+

Constructor

+ +

+ new BidsTsvFile(name, {{headers:, file, potentialSidecars, mergedDictionary, defManager) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + string + The name of the TSV file.
{{headers: + string[], rows: string[][]|Map[]|string} tsvData This file's TSV data. +
file + object + The file object representing this file.
potentialSidecars + Array.<string> + The list of potential JSON sidecars.
mergedDictionary + object + The merged bidsFile data.
defManager + DefinitionManager +
+ +
+
Source:
+
+ +
+ +
To Do:
+
+
    +
  • This interface is provisional and subject to modification in version 4.0.0.
  • +
+
+
+
+ +

Classes

+ +
+
BidsTsvFile
+
+
+ +

Members

+ +

+ hedColumnHedStrings + :Array.<string> +

+ +
HED strings in the "HED" column of the TSV data.
+ +
Type:
+
    +
  • + Array.<string> +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ isTimelineFile +

+ +
Whether this TSV file is a timeline file.
+ +
+
Source:
+
+ +
+
+ +

+ mergedSidecar + :BidsSidecar +

+ +
The pseudo-bidsFile object representing the merged bidsFile data.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ parsedTsv :Array.<Map> +

+ +
This file's parsed TSV data.
+ +
Type:
+
    +
  • + Array.<Map> +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ potentialSidecars :Array.<string> +

+ +
The list of potential JSON sidecars.
+ +
Type:
+
    +
  • + Array.<string> +
  • +
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ hasHedData() → {boolean} +

+ +
Determine whether this file has any HED data.
+ +
+
Source:
+
+ +
+ +
To Do:
+
+
    +
  • To be replaced with property in version 4.0.0.
  • +
+
+
+ +
Returns:
+ +
+
Type
+
+ boolean +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsTsvRow.html b/docs/html/BidsTsvRow.html new file mode 100644 index 00000000..9d44c556 --- /dev/null +++ b/docs/html/BidsTsvRow.html @@ -0,0 +1,294 @@ + + + + + JSDoc: Class: BidsTsvRow + + + + + + + + + +
+

Class: BidsTsvRow

+ +
+
+

+ BidsTsvRow(hedString, rowCells, tsvFile, tsvLine) +

+ +
A row in a BIDS TSV file.
+
+ +
+
+

Constructor

+ +

+ new BidsTsvRow(hedString, rowCells, tsvFile, tsvLine) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hedString + string + The parsed string representing this row.
rowCells + Map + The column-to-value mapping for this row.
tsvFile + BidsTsvFile + The file this row belongs to.
tsvLine + number + The line number in tsvFile this line is located at.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
BidsTsvRow
+
+
+ +

Members

+ +

+ rowCells :Map +

+ +
The map of column name to value for this row.
+ +
Type:
+
    +
  • + Map +
  • +
+ +
+
Source:
+
+ +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/BidsValidator.html b/docs/html/BidsValidator.html new file mode 100644 index 00000000..38653a72 --- /dev/null +++ b/docs/html/BidsValidator.html @@ -0,0 +1,363 @@ + + + + + JSDoc: Class: BidsValidator + + + + + + + + + +
+

Class: BidsValidator

+ +
+
+

+ BidsValidator(bidsFile, hedSchemas) +

+ +
Validator base class for HED data in BIDS TSV files.
+
+ +
+
+

Constructor

+ +

+ new BidsValidator(bidsFile, hedSchemas) +

+ +
Bids validator base class.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
bidsFile + BidsFile + The BIDS TSV file being validated.
hedSchemas + Schemas + The HED schemas used for validation.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
BidsValidator
+
+
+ +

Members

+ +

+ bidsFile + :BidsFile +

+ +
The BIDS file being validated.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ hedSchemas + :Schemas +

+ +
The HED schema collection being validated against.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ issues + :Array.<BidsIssue> +

+ +
The issues found during validation.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ validate() → {Array.<BidsIssue>} +

+ +
+ Validate a BIDS TSV file. This method returns the complete issue list for convenience. +
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- Any issues found during validation of this TSV file.
+ +
+
Type
+
+ Array.<BidsIssue> +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/ColumnSpliceSpec.html b/docs/html/ColumnSpliceSpec.html new file mode 100644 index 00000000..a8d061df --- /dev/null +++ b/docs/html/ColumnSpliceSpec.html @@ -0,0 +1,235 @@ + + + + + JSDoc: Class: ColumnSpliceSpec + + + + + + + + + +
+

Class: ColumnSpliceSpec

+ +
+
+

+ ColumnSpliceSpec() +

+ +
A specification for a tokenized column splice template.
+
+ + +
+
+ + + +
+ + + + + + + diff --git a/docs/html/DefinitionChecker_DefinitionChecker.html b/docs/html/DefinitionChecker_DefinitionChecker.html new file mode 100644 index 00000000..e05e333f --- /dev/null +++ b/docs/html/DefinitionChecker_DefinitionChecker.html @@ -0,0 +1,227 @@ + + + + + JSDoc: Class: DefinitionChecker + + + + + + + + + +
+

Class: DefinitionChecker

+ +
+
+

+ DefinitionChecker(hedString) +

+
+ +
+
+

+ new DefinitionChecker(hedString) +

+ +
+ Check Def-expand or definition syntax for compatible tags and number of groups +
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hedString + ParsedHedString + A group to check for Def-expand syntax.
+ +
+
Source:
+
+ +
+
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/Definition_Definition.html b/docs/html/Definition_Definition.html new file mode 100644 index 00000000..68df06e3 --- /dev/null +++ b/docs/html/Definition_Definition.html @@ -0,0 +1,225 @@ + + + + + JSDoc: Class: Definition + + + + + + + + + +
+

Class: Definition

+ +
+
+

+ Definition(definitionGroup) +

+
+ +
+
+

+ new Definition(definitionGroup) +

+ +
A single definition
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
definitionGroup + ParsedHedGroup + the parsedHedGroup representing the definition.
+ +
+
Source:
+
+ +
+
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/GroupSpec.html b/docs/html/GroupSpec.html new file mode 100644 index 00000000..ee73b60c --- /dev/null +++ b/docs/html/GroupSpec.html @@ -0,0 +1,236 @@ + + + + + JSDoc: Class: GroupSpec + + + + + + + + + +
+

Class: GroupSpec

+ +
+
+

+ GroupSpec() +

+ +
A specification for a tokenized tag group.
+
+ + +
+
+ + + +
+ + + + + + + diff --git a/docs/html/HedStringParser.html b/docs/html/HedStringParser.html new file mode 100644 index 00000000..e1d595cb --- /dev/null +++ b/docs/html/HedStringParser.html @@ -0,0 +1,498 @@ + + + + + JSDoc: Class: HedStringParser + + + + + + + + + +
+

Class: HedStringParser

+ +
+
+

+ HedStringParser(hedString, hedSchemas, definitionsAllowed, placeholdersAllowed) +

+ +
A parser for HED strings.
+
+ +
+
+

Constructor

+ +

+ new HedStringParser(hedString, hedSchemas, definitionsAllowed, placeholdersAllowed) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hedString + string + | + + ParsedHedString + The HED string to be parsed.
hedSchemas + Schemas + The collection of HED schemas.
definitionsAllowed + boolean + True if definitions are allowed
placeholdersAllowed + boolean + True if placeholders are allowed
+ +
+
Source:
+
+ +
+
+
+ +

Members

+ +

+ definitionsAllowed :boolean +

+ +
True if definitions are allowed in this string.
+ +
Type:
+
    +
  • + boolean +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ hedSchemas + :Schemas +

+ +
The collection of HED schemas.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ hedString + :string|ParsedHedString +

+ +
The HED string being parsed.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ placeholdersAllowed :boolean +

+ +
True if placeholders are allowed in this string.
+ +
Type:
+
    +
  • + boolean +
  • +
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ parseHedString() → {Array} +

+ +
Parse a full HED string.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+ - [ParsedHedString|null, Issue[]] representing the parsed HED string and any parsing issues. +
+ +
+
Type
+
+ Array +
+
+ +

+ (static) parseHedStrings(hedStrings, hedSchemas, definitionsAllowed, placeholdersAllowed) → {Array} +

+ +
Parse a list of HED strings.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hedStrings + Array.<string> + | + + Array.<ParsedHedString> + A list of HED strings.
hedSchemas + Schemas + The collection of HED schemas.
definitionsAllowed + boolean + True if definitions are allowed
placeholdersAllowed + boolean + True if placeholders are allowed
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+ - [ParsedHedString[], Issue[]] representing the parsed HED strings and any issues found. +
+ +
+
Type
+
+ Array +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/HedStringTokenizer.html b/docs/html/HedStringTokenizer.html new file mode 100644 index 00000000..ee293646 --- /dev/null +++ b/docs/html/HedStringTokenizer.html @@ -0,0 +1,242 @@ + + + + + JSDoc: Class: HedStringTokenizer + + + + + + + + + +
+

Class: HedStringTokenizer

+ +
+
+

+ HedStringTokenizer() +

+ +
Class for tokenizing HED strings.
+
+ +
+
+

Constructor

+ +

+ new HedStringTokenizer() +

+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
HedStringTokenizer
+
+
+ +

Methods

+ +

+ tokenize() → {Array} +

+ +
Split the HED string into delimiters and tags.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+ - [TagSpec[], GroupSpec, Issue[]] representing the tag specifications, group bounds, and any issues found. +
+ +
+
Type
+
+ Array +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/Issue.html b/docs/html/Issue.html new file mode 100644 index 00000000..d8f9ebba --- /dev/null +++ b/docs/html/Issue.html @@ -0,0 +1,534 @@ + + + + + JSDoc: Class: Issue + + + + + + + + + +
+

Class: Issue

+ +
+
+

+ Issue(internalCode, hedCode, level, parameters) +

+ +
A HED validation error or warning.
+
+ +
+
+

Constructor

+ +

+ new Issue(internalCode, hedCode, level, parameters) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
internalCode + string + The internal error code.
hedCode + string + The HED 3 error code.
level + string + The issue level (error or warning).
parameters + Object + The error string parameters.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
Issue
+
+
+ +

Members

+ +

+ hedCode :string +

+ +
The HED 3 error code.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ internalCode :string +

+ +
The internal error code.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ level :string +

+ +
The issue level (error or warning).
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ message :string +

+ +
The detailed error message.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ parameters :Object +

+ +
+ The parameters to the error message template. Object with string and map parameters. +
+ +
Type:
+
    +
  • + Object +
  • +
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ generateMessage() +

+ +
(Re-)generate the issue message.
+ +
+
Source:
+
+ +
+
+ +

+ isError() → {boolean} +

+ +
Whether this issue is an error.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+
Type
+
+ boolean +
+
+ +

+ toString() → {string} +

+ +
Override of Object.prototype.toString.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
This issue's message.
+ +
+
Type
+
+ string +
+
+ +

+ (static) issueListWithValidStatus(issues) → {Array} +

+ +
Return a tuple with a boolean denoting overall validity and all issues.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
issues + Array.<Issue> + A list of issues.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+ Returns [boolean, Issue[]] indicate if validation succeeded (i.e. any errors were found)and all issues (both + errors and warnings). +
+ +
+
Type
+
+ Array +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/ParsedHedColumnSplice.html b/docs/html/ParsedHedColumnSplice.html new file mode 100644 index 00000000..c1551657 --- /dev/null +++ b/docs/html/ParsedHedColumnSplice.html @@ -0,0 +1,311 @@ + + + + + JSDoc: Class: ParsedHedColumnSplice + + + + + + + + + +
+

Class: ParsedHedColumnSplice

+ +
+
+

+ ParsedHedColumnSplice(columnName, bounds) +

+ +
+ A template for an inline column splice in a ParsedHedString or + ParsedHedGroup. +
+
+ +
+
+

Constructor

+ +

+ new ParsedHedColumnSplice(columnName, bounds) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
columnName + string + The token for this tag.
bounds + Array.<number> + The collection of HED schemas.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
ParsedHedColumnSplice
+
+
+ +

Methods

+ +

+ format(long) → {string} +

+ +
Nicely format this column splice template.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
long + boolean + trueWhether the tags should be in long form.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+
Type
+
+ string +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/ParsedHedString.html b/docs/html/ParsedHedString.html new file mode 100644 index 00000000..939069bd --- /dev/null +++ b/docs/html/ParsedHedString.html @@ -0,0 +1,575 @@ + + + + + JSDoc: Class: ParsedHedString + + + + + + + + + +
+

Class: ParsedHedString

+ +
+
+

+ ParsedHedString(hedString, parsedTags) +

+ +
A parsed HED string.
+
+ +
+
+

Constructor

+ +

+ new ParsedHedString(hedString, parsedTags) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hedString + string + The original HED string.
parsedTags + Array.<ParsedHedSubstring> + The nested list of parsed HED tags and groups.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
ParsedHedString
+
+
+ +

Members

+ +

+ columnSplices + :Array.<ParsedHedColumnSplice> +

+ +
All the column splices in the string at all levels.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ definitions + :Array.<ParsedHedGroup> +

+ +
The top-level definition tag groups in the string.
+ +
Type:
+
    +
  • + Array.<ParsedHedGroup> +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ hedString :string +

+ +
The original HED string.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ parseTree + :Array.<ParsedHedSubstring> +

+ +
The parsed substring data in unfiltered form.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ tagGroups :Array.<ParsedHedGroup> +

+ +
The tag groups in the string (top-level).
+ +
Type:
+
    +
  • + Array.<ParsedHedGroup> +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ tags :Array.<ParsedHedTag> +

+ +
All the tags in the string at all levels
+ +
Type:
+
    +
  • + Array.<ParsedHedTag> +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ topLevelGroupTags + :Array.<Array.<ParsedHedTag>> +

+ +
The tags in the top-level tag groups in the string, split into arrays.
+ +
Type:
+
    +
  • + Array.<Array.<ParsedHedTag>> +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ topLevelTags + :Array.<ParsedHedTag> +

+ +
All the top-level tags in the string.
+ +
Type:
+
    +
  • + Array.<ParsedHedTag> +
  • +
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ _getNormalized() → {string} +

+ +
Return a normalized string representation
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+
Type
+
+ string +
+
+ +

+ format(long) → {string} +

+ +
Nicely format this HED string. (Doesn't allow column splices).
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
long + boolean + trueWhether the tags should be in long form.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+
Type
+
+ string +
+
+ +

+ toString() → {string} +

+ +
Override of Object.prototype.toString.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+
Type
+
+ string +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/ParsedHedSubstring.html b/docs/html/ParsedHedSubstring.html new file mode 100644 index 00000000..2e326fd8 --- /dev/null +++ b/docs/html/ParsedHedSubstring.html @@ -0,0 +1,410 @@ + + + + + JSDoc: Class: ParsedHedSubstring + + + + + + + + + +
+

Class: ParsedHedSubstring

+ +
+
+

+ ParsedHedSubstring(originalTag, originalBounds) +

+ +
A parsed HED substring.
+
+ +
+
+

Constructor

+ +

+ new ParsedHedSubstring(originalTag, originalBounds) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
originalTag + string + The original HED tag.
originalBounds + Array.<number> + The bounds of the HED tag in the original HED string.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
ParsedHedSubstring
+
+
+ +

Members

+ +

+ (abstract) normalized +

+ +
Get the normalized version of the object.
+ +
+
Source:
+
+ +
+
+ +

+ originalBounds :Array.<int> +

+ +
The bounds of the HED tag in the original HED string.
+ +
Type:
+
    +
  • + Array.<int> +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ originalTag :string +

+ +
The original pre-parsed version of the HED tag.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ (abstract) format(long) → {string} +

+ +
+ Nicely format this substring. This is left blank for the subclasses to override. This is left blank for the + subclasses to override. +
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
long + boolean + trueWhether the tags should be in long form.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+
Type
+
+ string +
+
+ +

+ toString() → {string} +

+ +
Override of Object.prototype.toString.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The original form of this HED substring.
+ +
+
Type
+
+ string +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/PartneredSchema.html b/docs/html/PartneredSchema.html new file mode 100644 index 00000000..a3eed84f --- /dev/null +++ b/docs/html/PartneredSchema.html @@ -0,0 +1,265 @@ + + + + + JSDoc: Class: PartneredSchema + + + + + + + + + +
+

Class: PartneredSchema

+ +
+
+

+ PartneredSchema(actualSchemas) +

+ +
An imported lazy partnered HED 3 schema.
+
+ +
+
+

Constructor

+ +

+ new PartneredSchema(actualSchemas) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
actualSchemas + Array.<Schema> + The actual HED 3 schemas underlying this partnered schema.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
PartneredSchema
+
+
+ +

Members

+ +

+ actualSchemas + :Array.<Schema> +

+ +
The actual HED 3 schemas underlying this partnered schema.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/Schema.html b/docs/html/Schema.html new file mode 100644 index 00000000..ac4a7a27 --- /dev/null +++ b/docs/html/Schema.html @@ -0,0 +1,468 @@ + + + + + JSDoc: Class: Schema + + + + + + + + + +
+

Class: Schema

+ +
+
+

+ Schema(xmlData, entries) +

+ +
An imported HED 3 schema.
+
+ +
+
+

Constructor

+ +

+ new Schema(xmlData, entries) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xmlData + object + The schema XML data.
entries + SchemaEntries + A collection of schema entries.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
Schema
+
+
+ +

Members

+ +

+ entries + :SchemaEntries +

+ +
The collection of schema entries.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ generation :Number +

+ +
The HED generation of this schema.
+ +
Type:
+
    +
  • + Number +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ library :string +

+ +
The HED library schema name.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ prefix :string +

+ +
This schema's prefix in the active schema set.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ version :string +

+ +
The HED schema version.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ withStandard :string +

+ +
The standard HED schema version this schema is linked to.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ tagHasAttribute(tag, tagAttribute) → {boolean} +

+ +
Determine if a HED tag has a particular attribute in this schema.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tag + string + The HED tag to check.
tagAttribute + string + The attribute to check for.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
Whether this tag has this attribute.
+ +
+
Type
+
+ boolean +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaAttribute.html b/docs/html/SchemaAttribute.html new file mode 100644 index 00000000..c5d59943 --- /dev/null +++ b/docs/html/SchemaAttribute.html @@ -0,0 +1,383 @@ + + + + + JSDoc: Class: SchemaAttribute + + + + + + + + + +
+

Class: SchemaAttribute

+ +
+
+

+ SchemaAttribute(name, properties) +

+ +
A schema attribute.
+
+ +
+
+

Constructor

+ +

+ new SchemaAttribute(name, properties) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + string + The name of the schema attribute.
properties + Array.<SchemaProperty> + The properties assigned to this schema attribute.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SchemaAttribute
+
+
+ +

Members

+ +

+ _categoryProperties + :Set.<SchemaProperty> +

+ +
The categories of elements this schema attribute applies to.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ _roleProperties + :Set.<SchemaProperty> +

+ +
The set of role properties for this schema attribute.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ _typeProperty + :SchemaProperty +

+ +
The data type of this schema attribute.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ categoryProperty +

+ +
The categories of elements this schema attribute applies to.
+ +
+
Source:
+
+ +
+
+ +

+ roleProperties +

+ +
The set of role properties for this schema attribute.
+ +
+
Source:
+
+ +
+
+ +

+ typeProperty +

+ +
The data type property of this schema attribute.
+ +
+
Source:
+
+ +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaEntries.html b/docs/html/SchemaEntries.html new file mode 100644 index 00000000..e08cb373 --- /dev/null +++ b/docs/html/SchemaEntries.html @@ -0,0 +1,552 @@ + + + + + JSDoc: Class: SchemaEntries + + + + + + + + + +
+

Class: SchemaEntries

+ +
+
+

+ SchemaEntries(schemaParser) +

+ +
SchemaEntries class
+
+ +
+
+

Constructor

+ +

+ new SchemaEntries(schemaParser) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaParser + SchemaParser + A constructed schema parser.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SchemaEntries
+
+
+ +

Members

+ +

+ SIUnitModifiers +

+ +
Get the schema's SI unit modifiers.
+ +
+
Source:
+
+ +
+
+ +

+ SIUnitSymbolModifiers +

+ +
Get the schema's SI unit symbol modifiers.
+ +
+
Source:
+
+ +
+
+ +

+ allUnits +

+ +
Get a map of all of this schema's units.
+ +
+
Source:
+
+ +
+
+ +

+ attributes + :SchemaEntryManager.<SchemaAttribute> +

+ +
The schema's attributes.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ properties + :SchemaEntryManager.<SchemaProperty> +

+ +
The schema's properties.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ tags + :SchemaTagManager +

+ +
The schema's tags.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ unitClasses + :SchemaEntryManager.<SchemaUnitClass> +

+ +
The schema's unit classes.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ unitModifiers + :SchemaEntryManager.<SchemaUnitModifier> +

+ +
The schema's unit modifiers.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ valueClasses + :SchemaEntryManager.<SchemaValueClass> +

+ +
The schema's value classes.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ tagHasAttribute(tag, tagAttribute) → {boolean} +

+ +
Determine if a HED tag has a particular attribute in this schema.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tag + string + The HED tag to check.
tagAttribute + string + The attribute to check for.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
Whether this tag has this attribute.
+ +
+
Type
+
+ boolean +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaEntry.html b/docs/html/SchemaEntry.html new file mode 100644 index 00000000..0209cd5d --- /dev/null +++ b/docs/html/SchemaEntry.html @@ -0,0 +1,311 @@ + + + + + JSDoc: Class: SchemaEntry + + + + + + + + + +
+

Class: SchemaEntry

+ +
+
+

+ SchemaEntry() +

+ +
SchemaEntry class
+
+ +
+
+

Constructor

+ +

+ new SchemaEntry() +

+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SchemaEntry
+
+
+ +

Members

+ +

+ _name :string +

+ +
The name of this schema entry.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

name

+ +
The name of this schema entry.
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ hasAttributeName(attributeName) → {boolean} +

+ +
+ Whether this schema entry has this attribute (by name). This method is a stub to be overridden in + SchemaEntryWithAttributes. +
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
attributeName + string + The attribute to check for.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
Whether this schema entry has this attribute.
+ +
+
Type
+
+ boolean +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaEntryManager.html b/docs/html/SchemaEntryManager.html new file mode 100644 index 00000000..955e4128 --- /dev/null +++ b/docs/html/SchemaEntryManager.html @@ -0,0 +1,635 @@ + + + + + JSDoc: Class: SchemaEntryManager + + + + + + + + + +
+

Class: SchemaEntryManager

+ +
+
+

+ SchemaEntryManager(definitions) +

+ +
A manager of SchemaEntry objects.
+
+ +
+
+

Constructor

+ +

+ new SchemaEntryManager(definitions) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
definitions + Map.<string, T> + A map of schema entry definitions.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SchemaEntryManager
+
+
+ +

Members

+ +

+ _definitions :Map.<string, T> +

+ +
The definitions managed by this entry manager.
+ +
Type:
+
    +
  • + Map.<string, T> +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ length +

+ +
The number of entries in this collection.
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ filter(fn) → {Map} +

+ +
Filter the map underlying this manager.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fn + function + ([string, T]): boolean specifying the filtering function.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- string->T representing a collection of entries with that attribute.
+ +
+
Type
+
+ Map +
+
+ +

+ getEntriesWithBooleanAttribute(booleanAttributeName) → {Map} +

+ +
Get a collection of entries with the given boolean attribute.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
booleanAttributeName + string + The name of boolean attribute to filter on.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- string->T representing a collection of entries with that attribute.
+ +
+
Type
+
+ Map +
+
+ +

+ getEntry(name) → {T} +

+ +
Get the entry with the given name.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + string + The name of the entry to retrieve.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- The entry with that name.
+ +
+
Type
+
+ T +
+
+ +

+ hasEntry(name) → {boolean} +

+ +
Determine whether the entry with the given name exists.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + string + The name of the entry.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
Whether the entry exists.
+ +
+
Type
+
+ boolean +
+
+ +

+ keys() → {IterableIterator} +

+ +
Iterator over the entry manager's keys.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- [string]
+ +
+
Type
+
+ IterableIterator +
+
+ +

+ values() → {IterableIterator} +

+ +
Iterator over the entry manager's keys.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- [T]
+ +
+
Type
+
+ IterableIterator +
+
+ +

+ (protected, static) _filterDefinitionMap(definitionMap, fn) → {Map} +

+ +
Filter a definition map.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
definitionMap + Map.<string, T> + The definition map.
fn + function + ([string, T]):boolean specifying the filtering function.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- string->T representing the filtered definitions.
+ +
+
Type
+
+ Map +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaEntryWithAttributes.html b/docs/html/SchemaEntryWithAttributes.html new file mode 100644 index 00000000..7d2a25c0 --- /dev/null +++ b/docs/html/SchemaEntryWithAttributes.html @@ -0,0 +1,572 @@ + + + + + JSDoc: Class: SchemaEntryWithAttributes + + + + + + + + + +
+

Class: SchemaEntryWithAttributes

+ +
+
+

+ SchemaEntryWithAttributes() +

+ +
SchemaEntryWithAttributes class
+
+ +
+
+

Constructor

+ +

+ new SchemaEntryWithAttributes() +

+ +
+
Source:
+
+ +
+
+
+ +

Members

+ +

+ booleanAttributeNames + :Set.<string> +

+ +
The set of boolean attribute names this schema entry has.
+ +
Type:
+
    +
  • + Set.<string> +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ booleanAttributes + :Set.<SchemaAttribute> +

+ +
The set of boolean attributes this schema entry has.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ valueAttributeNames + :Map.<string, *> +

+ +
The collection of value attribute names this schema entry has.
+ +
Type:
+
    +
  • + Map.<string, *> +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ valueAttributes + :Map.<SchemaAttribute, *> +

+ +
The collection of value attributes this schema entry has.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ getAttributeValue(attribute, alwaysReturnArray) → {*} +

+ +
Retrieve the value of an attribute on this schema entry.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
attribute + SchemaAttribute + The attribute whose value should be returned.
alwaysReturnArray + boolean + falseWhether to return a singleton array instead of a scalar value.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The value of the attribute.
+ +
+
Type
+
+ * +
+
+ +

+ getNamedAttributeValue(attributeName, alwaysReturnArray) → {*} +

+ +
Retrieve the value of an attribute (by name) on this schema entry.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
attributeName + string + The attribute whose value should be returned.
alwaysReturnArray + boolean + falseWhether to return a singleton array instead of a scalar value.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The value of the attribute.
+ +
+
Type
+
+ * +
+
+ +

+ hasAttribute(attribute) → {boolean} +

+ +
Whether this schema entry has this attribute.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
attribute + SchemaAttribute + The attribute to check for.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
Whether this schema entry has this attribute.
+ +
+
Type
+
+ boolean +
+
+ +

+ hasAttributeName(attributeName) → {boolean} +

+ +
Whether this schema entry has this attribute (by name).
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
attributeName + string + The attribute to check for.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
Whether this schema entry has this attribute.
+ +
+
Type
+
+ boolean +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaProperty.html b/docs/html/SchemaProperty.html new file mode 100644 index 00000000..7115189e --- /dev/null +++ b/docs/html/SchemaProperty.html @@ -0,0 +1,289 @@ + + + + + JSDoc: Class: SchemaProperty + + + + + + + + + +
+

Class: SchemaProperty

+ +
+
+

+ SchemaProperty() +

+ +
A schema property.
+
+ +
+
+

Constructor

+ +

+ new SchemaProperty() +

+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SchemaProperty
+
+
+ +

Members

+ +

+ _propertyType :string +

+ +
The type of the property.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ isCategoryProperty +

+ +
Whether this property describes a schema category.
+ +
+
Source:
+
+ +
+
+ +

+ isRoleProperty +

+ +
Whether this property describes a role.
+ +
+
Source:
+
+ +
+
+ +

+ isTypeProperty +

+ +
Whether this property describes a data type.
+ +
+
Source:
+
+ +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaSpec.html b/docs/html/SchemaSpec.html new file mode 100644 index 00000000..85169571 --- /dev/null +++ b/docs/html/SchemaSpec.html @@ -0,0 +1,397 @@ + + + + + JSDoc: Class: SchemaSpec + + + + + + + + + +
+

Class: SchemaSpec

+ +
+
+

+ SchemaSpec(nickname, version, librarynullable, localPathnullable) +

+ +
A schema version specification.
+
+ +
+
+

Constructor

+ +

+ new SchemaSpec(nickname, version, librarynullable, localPathnullable) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
nickname + string + The nickname of this schema.
version + string + The version of this schema.
library + string + <nullable>
The library name of this schema.
localPath + string + <nullable>
The local path for this schema.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SchemaSpec
+
+
+ +

Members

+ +

+ library :string +

+ +
The library name of this schema.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ localName +

+ +
Compute the name for the bundled copy of this schema.
+ +
+
Source:
+
+ +
+
+ +

+ localPath :string +

+ +
The local path for this schema.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ nickname :string +

+ +
The nickname of this schema.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ version :string +

+ +
The version of this schema.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaTag.html b/docs/html/SchemaTag.html new file mode 100644 index 00000000..5f0a9265 --- /dev/null +++ b/docs/html/SchemaTag.html @@ -0,0 +1,600 @@ + + + + + JSDoc: Class: SchemaTag + + + + + + + + + +
+

Class: SchemaTag

+ +
+
+

+ SchemaTag(name, booleanAttributes, valueAttributes, unitClasses, valueClasses) +

+ +
A tag in a HED schema.
+
+ +
+
+

Constructor

+ +

+ new SchemaTag(name, booleanAttributes, valueAttributes, unitClasses, valueClasses) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + string + The name of this tag.
booleanAttributes + Set.<SchemaAttribute> + The boolean attributes for this tag.
valueAttributes + Map.<SchemaAttribute, *> + The value attributes for this tag.
unitClasses + Array.<SchemaUnitClass> + The unit classes for this tag.
valueClasses + Array.<SchemaValueClass> + The value classes for this tag.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SchemaTag
+
+
+ +

Members

+ +

+ ancestors +

+ +
Return all of this tag's ancestors.
+ +
+
Source:
+
+ +
+
+ +

+ hasUnitClasses +

+ +
Whether this tag has any unit classes.
+ +
+
Source:
+
+ +
+
+ +

+ hasValueClasses +

+ +
Whether this tag has any value classes.
+ +
+
Source:
+
+ +
+
+ +

+ longName +

+ +
This tag's long name.
+ +
+
Source:
+
+ +
+
+ +

+ parent + :SchemaTag +

+ +
This tag's parent tag.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ parent +

+ +
Set the tag's parent tag.
+ +
+
Source:
+
+ +
+
+ +

+ unitClasses + :Array.<SchemaUnitClass> +

+ +
This tag's unit classes.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ valueClasses + :Array.<SchemaValueClass> +

+ +
This tag's value classes.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ valueTag +

+ +
This tag's value-taking child tag.
+ +
+
Source:
+
+ +
+
+ +

+ valueTag +

+ +
Set the tag's value-taking child tag.
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ extend(extension) → {string} +

+ +
Extend this tag's short name.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
extension + string + The extension.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The extended short string.
+ +
+
Type
+
+ string +
+
+ +

+ longExtend(extension) → {string} +

+ +
Extend this tag's long name.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
extension + string + The extension.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The extended long string.
+ +
+
Type
+
+ string +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaTagManager.html b/docs/html/SchemaTagManager.html new file mode 100644 index 00000000..4e948b3d --- /dev/null +++ b/docs/html/SchemaTagManager.html @@ -0,0 +1,454 @@ + + + + + JSDoc: Class: SchemaTagManager + + + + + + + + + +
+

Class: SchemaTagManager

+ +
+
+

+ SchemaTagManager(byShortName, byLongName) +

+ +
A manager of SchemaTag objects.
+
+ +
+
+

Constructor

+ +

+ new SchemaTagManager(byShortName, byLongName) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
byShortName + Map.<string, SchemaTag> + The mapping of tags by short name.
byLongName + Map.<string, SchemaTag> + The mapping of tags by long name.
+ +
+
Source:
+
+ +
+
+
+ +

Extends

+ + + +

Classes

+ +
+
SchemaTagManager
+
+
+ +

Members

+ +

+ _definitionsByLongName + :Map.<string, SchemaTag> +

+ +
The mapping of tags by long name.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ filterByLongName(fn) → {Map} +

+ +
Filter the map underlying this manager using the long name.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fn + function + ([string, SchemaTag]): boolean specifying the filtering function.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- string --> SchemaTag representing the filtered map.
+ +
+
Type
+
+ Map +
+
+ +

+ getLongNameEntry(longName) → {SchemaTag} +

+ +
Get the tag with the given name.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
longName + string + The long name of the tag to retrieve.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- The tag with that name.
+ +
+
Type
+
+ SchemaTag +
+
+ +

+ hasLongNameEntry(longName) → {boolean} +

+ +
Determine whether the tag with the given name exists.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
longName + string + The long name of the tag.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
-True if the tag exists.
+ +
+
Type
+
+ boolean +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaUnit.html b/docs/html/SchemaUnit.html new file mode 100644 index 00000000..bd9048a0 --- /dev/null +++ b/docs/html/SchemaUnit.html @@ -0,0 +1,358 @@ + + + + + JSDoc: Class: SchemaUnit + + + + + + + + + +
+

Class: SchemaUnit

+ +
+
+

+ SchemaUnit(name, booleanAttributes, valueAttributes, unitModifiers) +

+ +
SchemaUnit class
+
+ +
+
+

Constructor

+ +

+ new SchemaUnit(name, booleanAttributes, valueAttributes, unitModifiers) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + string + The name of the unit.
booleanAttributes + Set.<SchemaAttribute> + This unit's boolean attributes.
valueAttributes + Map.<SchemaAttribute, *> + This unit's key-value attributes.
unitModifiers + SchemaEntryManager.<SchemaUnitModifier> + The collection of unit modifiers.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SchemaUnit
+
+
+ +

Members

+ +

+ _derivativeUnits :Array.<string> +

+ +
The legal derivatives of this unit.
+ +
Type:
+
    +
  • + Array.<string> +
  • +
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ validateUnit(value) → {boolean} +

+ +
Determine if a value has this unit.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + string + + - either the whole value or the part after a blank (if not a prefix unit) +
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
Whether the value has these units.
+ +
+
Type
+
+ boolean +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaUnitClass.html b/docs/html/SchemaUnitClass.html new file mode 100644 index 00000000..fe42559a --- /dev/null +++ b/docs/html/SchemaUnitClass.html @@ -0,0 +1,364 @@ + + + + + JSDoc: Class: SchemaUnitClass + + + + + + + + + +
+

Class: SchemaUnitClass

+ +
+
+

+ SchemaUnitClass(name, booleanAttributes, valueAttributes, units) +

+ +
SchemaUnitClass class
+
+ +
+
+

Constructor

+ +

+ new SchemaUnitClass(name, booleanAttributes, valueAttributes, units) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + string + The name of this unit class.
booleanAttributes + Set.<SchemaAttribute> + The boolean attributes for this unit class.
valueAttributes + Map.<SchemaAttribute, *> + The value attributes for this unit class.
units + Map.<string, SchemaUnit> + The units for this unit class.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SchemaUnitClass
+
+
+ +

Members

+ +

+ _units + :Map.<string, SchemaUnit> +

+ +
The units for this unit class.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

+ defaultUnit +

+ +
Get the default unit for this unit class.
+ +
+
Source:
+
+ +
+
+ +

units

+ +
Get the units for this unit class.
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ extractUnit() → {Array} +

+ +
Extracts the Unit class and remainder
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+ [SchemaUnit, string, string] containing unit class, unit string, and value string +
+ +
+
Type
+
+ Array +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaUnitModifier.html b/docs/html/SchemaUnitModifier.html new file mode 100644 index 00000000..a743b8fb --- /dev/null +++ b/docs/html/SchemaUnitModifier.html @@ -0,0 +1,208 @@ + + + + + JSDoc: Class: SchemaUnitModifier + + + + + + + + + +
+

Class: SchemaUnitModifier

+ +
+
+

+ SchemaUnitModifier() +

+ +
SchemaUnitModifier class
+
+ + +
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaValueClass.html b/docs/html/SchemaValueClass.html new file mode 100644 index 00000000..0b7c7c31 --- /dev/null +++ b/docs/html/SchemaValueClass.html @@ -0,0 +1,335 @@ + + + + + JSDoc: Class: SchemaValueClass + + + + + + + + + +
+

Class: SchemaValueClass

+ +
+
+

+ SchemaValueClass(name, booleanAttributes, valueAttributes, charClassRegex, wordRegex) +

+ +
SchemaValueClass class
+
+ +
+
+

Constructor

+ +

+ new SchemaValueClass(name, booleanAttributes, valueAttributes, charClassRegex, wordRegex) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + string + The name of this value class.
booleanAttributes + Set.<SchemaAttribute> + The boolean attributes for this value class.
valueAttributes + Map.<SchemaAttribute, *> + The value attributes for this value class.
charClassRegex + RegExp + The character class-based regular expression for this value class.
wordRegex + RegExp + The "word form"-based regular expression for this value class.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SchemaValueClass
+
+
+ +

Methods

+ +

+ validateValue(value) → {boolean} +

+ +
Determine if a value is valid according to this value class.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + string + A HED value.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
Whether the value conforms to this value class.
+ +
+
Type
+
+ boolean +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemaValueTag.html b/docs/html/SchemaValueTag.html new file mode 100644 index 00000000..52cc4a59 --- /dev/null +++ b/docs/html/SchemaValueTag.html @@ -0,0 +1,335 @@ + + + + + JSDoc: Class: SchemaValueTag + + + + + + + + + +
+

Class: SchemaValueTag

+ +
+
+

+ SchemaValueTag() +

+ +
A value-taking tag in a HED schema.
+
+ +
+
+

Constructor

+ +

+ new SchemaValueTag() +

+ +
+
Source:
+
+ +
+
+
+ +

Members

+ +

+ longName +

+ +
This tag's long name.
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ extend(extension) → {string} +

+ +
Extend this tag's short name.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
extension + string + The extension.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The extended short string.
+ +
+
Type
+
+ string +
+
+ +

+ longExtend(extension) → {string} +

+ +
Extend this tag's long name.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
extension + string + The extension.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The extended long string.
+ +
+
Type
+
+ string +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/Schemas.html b/docs/html/Schemas.html new file mode 100644 index 00000000..92adb4ad --- /dev/null +++ b/docs/html/Schemas.html @@ -0,0 +1,454 @@ + + + + + JSDoc: Class: Schemas + + + + + + + + + +
+

Class: Schemas

+ +
+
+

+ Schemas(schemas) +

+ +
The collection of active HED schemas.
+
+ +
+
+

Constructor

+ +

+ new Schemas(schemas) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemas + Schema + | + + Map.<string, Schema> + | + + null + The imported HED schemas.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
Schemas
+
+
+ +

Members

+ +

+ baseSchema +

+ +
The base schema, i.e. the schema with no nickname, if one is defined.
+ +
+
Source:
+
+ +
+
+ +

+ generation :Number +

+ +
+ The HED generation of this schema. If baseSchema is null, generation is set to 0. +
+ +
Type:
+
    +
  • + Number +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ isHed3 +

+ +
Whether this schema collection comprises HED 3 schemas.
+ +
+
Source:
+
+ +
+
+ +

+ isSyntaxOnly +

+ +
Whether this schema collection is for syntactic validation only.
+ +
+
Source:
+
+ +
+
+ +

+ librarySchemas +

+ +
The library schemas, i.e. the schema with nicknames, if any are defined.
+ +
+
Source:
+
+ +
+
+ +

+ schemas + :Map.<string, Schema>|null +

+ +
+ The imported HED schemas. The empty string key ("") corresponds to the schema with no nickname, while other + keys correspond to the respective nicknames. This field is null for syntax-only validation. +
+ +
Type:
+
    +
  • + Map.<string, Schema> + | + + null +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ standardSchema +

+ +
+ The standard schema, i.e. primary schema implementing the HED standard, if one is defined. +
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ getSchema(schemaName) → {Schema} +

+ +
Return the schema with the given nickname.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaName + string + A nickname in the schema set.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The schema object corresponding to that nickname.
+ +
+
Type
+
+ Schema +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SchemasSpec.html b/docs/html/SchemasSpec.html new file mode 100644 index 00000000..4254de38 --- /dev/null +++ b/docs/html/SchemasSpec.html @@ -0,0 +1,297 @@ + + + + + JSDoc: Class: SchemasSpec + + + + + + + + + +
+

Class: SchemasSpec

+ +
+
+

+ SchemasSpec() +

+ +
A specification mapping schema nicknames to SchemaSpec objects.
+
+ +
+
+

Constructor

+ +

+ new SchemasSpec() +

+ +
Constructor.
+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SchemasSpec
+
+
+ +

Members

+ +

+ data + :Map.<string, Array.<SchemaSpec>> +

+ +
The specification mapping data.
+ +
Type:
+ + +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ addSchemaSpec(schemaSpec) → {SchemasSpec|map} +

+ +
Add a schema to this specification.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaSpec + SchemaSpec + A schema specification.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
This object.
+ +
+
Type
+
+ SchemasSpec + | + + map +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/SubstringSpec.html b/docs/html/SubstringSpec.html new file mode 100644 index 00000000..ed9fd2e8 --- /dev/null +++ b/docs/html/SubstringSpec.html @@ -0,0 +1,235 @@ + + + + + JSDoc: Class: SubstringSpec + + + + + + + + + +
+

Class: SubstringSpec

+ +
+
+

+ SubstringSpec() +

+ +
A specification for a tokenized substring.
+
+ +
+
+

Constructor

+ +

+ new SubstringSpec() +

+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
SubstringSpec
+
+
+ +

Members

+ +

+ bounds :Array.<number> +

+ +
The starting and ending bounds of the substring.
+ +
Type:
+
    +
  • + Array.<number> +
  • +
+ +
+
Source:
+
+ +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/TagSpec.html b/docs/html/TagSpec.html new file mode 100644 index 00000000..26af9100 --- /dev/null +++ b/docs/html/TagSpec.html @@ -0,0 +1,259 @@ + + + + + JSDoc: Class: TagSpec + + + + + + + + + +
+

Class: TagSpec

+ +
+
+

+ TagSpec() +

+ +
A specification for a tokenized tag.
+
+ +
+
+

Constructor

+ +

+ new TagSpec() +

+ +
+
Source:
+
+ +
+
+
+ +

Classes

+ +
+
TagSpec
+
+
+ +

Members

+ +

+ library :string +

+ +
The schema prefix for this tag, if any.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+ +

+ tag :string +

+ +
The tag this spec represents.
+ +
Type:
+
    +
  • + string +
  • +
+ +
+
Source:
+
+ +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_schema.js.html b/docs/html/bids_schema.js.html new file mode 100644 index 00000000..3493da34 --- /dev/null +++ b/docs/html/bids_schema.js.html @@ -0,0 +1,279 @@ + + + + + JSDoc: Source: bids/schema.js + + + + + + + + + +
+

Source: bids/schema.js

+ +
+
+
import castArray from 'lodash/castArray'
+import semver from 'semver'
+
+import { buildSchemas } from '../schema/init'
+import { IssueError } from '../issues/issues'
+import { SchemaSpec, SchemasSpec } from '../schema/specs'
+
+const alphabeticRegExp = new RegExp('^[a-zA-Z]+$')
+
+/**
+ * Build a HED schema collection based on the defined BIDS schemas.
+ *
+ * @param {BidsJsonFile} datasetDescription The description of the BIDS dataset being validated.
+ * @param {SchemasSpec} schemaDefinition The version spec override for the schema to be loaded.
+ * @returns {Promise} A Promise with the schema collection, or null if the specification is missing.
+ * @throws {IssueError} If the schema specification is invalid.
+ */
+export async function buildBidsSchemas(datasetDescription, schemaDefinition) {
+  const schemasSpec = buildSchemasSpec(datasetDescription, schemaDefinition)
+  if (schemasSpec === null) {
+    return null
+  }
+  return buildSchemas(schemasSpec)
+}
+
+/**
+ * Build a HED schema specification based on the defined BIDS schemas.
+ *
+ * @param {BidsJsonFile} datasetDescription The description of the BIDS dataset being validated.
+ * @param {SchemasSpec} schemaDefinition The version spec override for the schema to be loaded.
+ * @returns {SchemasSpec|null} The schema specification to be used to build the schemas, or null if the specification is missing.
+ * @throws {IssueError} If the schema specification is invalid.
+ */
+export function buildSchemasSpec(datasetDescription, schemaDefinition) {
+  if (schemaDefinition) {
+    return validateSchemasSpec(schemaDefinition)
+  } else if (datasetDescription.jsonData?.HEDVersion) {
+    return parseSchemasSpec(datasetDescription.jsonData.HEDVersion)
+  } else {
+    return null
+  }
+}
+
+function validateSchemasSpec(schemasSpec) {
+  if (schemasSpec instanceof SchemasSpec) {
+    return schemasSpec
+  } else {
+    IssueError.generateAndThrow('invalidSchemaSpecification', { spec: JSON.stringify(schemasSpec) })
+  }
+}
+
+export function parseSchemasSpec(hedVersion) {
+  const schemasSpec = new SchemasSpec()
+  const processVersion = castArray(hedVersion)
+  for (const schemaVersion of processVersion) {
+    const schemaSpec = parseSchemaSpec(schemaVersion)
+    schemasSpec.addSchemaSpec(schemaSpec)
+  }
+  return schemasSpec
+}
+
+export function parseSchemaSpec(schemaVersion) {
+  const [nickname, schema] = splitNicknameAndSchema(schemaVersion)
+  const [library, version] = splitLibraryAndVersion(schema, schemaVersion)
+  return new SchemaSpec(nickname, version, library)
+}
+
+function splitNicknameAndSchema(schemaVersion) {
+  const nicknameSplit = schemaVersion.split(':')
+  let nickname = ''
+  let schema
+  if (nicknameSplit.length > 2) {
+    IssueError.generateAndThrow('invalidSchemaSpecification', { spec: schemaVersion })
+  }
+  if (nicknameSplit.length > 1) {
+    ;[nickname, schema] = nicknameSplit
+    if (!alphabeticRegExp.test(nickname)) {
+      IssueError.generateAndThrow('invalidSchemaNickname', { nickname: nickname, spec: schemaVersion })
+    }
+  } else {
+    schema = nicknameSplit[0]
+  }
+  return [nickname, schema]
+}
+
+function splitLibraryAndVersion(schemaVersion, originalVersion) {
+  const versionSplit = schemaVersion.split('_')
+  let library = ''
+  let version
+  if (versionSplit.length > 2) {
+    IssueError.generateAndThrow('invalidSchemaSpecification', { spec: originalVersion })
+  }
+  if (versionSplit.length > 1) {
+    ;[library, version] = versionSplit
+    if (!alphabeticRegExp.test(library)) {
+      IssueError.generateAndThrow('invalidSchemaSpecification', { spec: originalVersion })
+    }
+  } else {
+    version = versionSplit[0]
+  }
+  if (!semver.valid(version)) {
+    IssueError.generateAndThrow('invalidSchemaSpecification', { spec: originalVersion })
+  }
+  return [library, version]
+}
+
+//export default buildBidsSchemas
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_tsvParser.js.html b/docs/html/bids_tsvParser.js.html new file mode 100644 index 00000000..f1c124a2 --- /dev/null +++ b/docs/html/bids_tsvParser.js.html @@ -0,0 +1,234 @@ + + + + + JSDoc: Source: bids/tsvParser.js + + + + + + + + + +
+

Source: bids/tsvParser.js

+ +
+
+
/**
+ * Module for parsing TSV files.
+ *
+ * Adapted from https://github.com/bids-standard/bids-validator/blob/6fc6d152b52266934575442e61f1477ba18f42ec/bids-validator/validators/tsv/tsvParser.js
+ * and https://github.com/bids-standard/bids-validator/blob/a5c63b445e3103bcc0843deac192033a9f0b4c5b/bids-validator/src/files/tsv.ts
+ */
+
+const stripBOM = (str) => str.replace(/^\uFEFF/, '')
+const normalizeEOL = (str) => str.replace(/\r\n/g, '\n').replace(/\r/g, '\n')
+const isContentfulRow = (row) => row && !/^\s*$/.test(row)
+
+/**
+ * Parse a TSV file.
+ *
+ * @param {string} contents The contents of a TSV file.
+ * @returns {Map[]} The parsed contents of the TSV file.
+ */
+export function parseTSV(contents) {
+  const columns = new Map()
+  const rows = stripBOM(normalizeEOL(contents))
+    .split('\n')
+    .filter(isContentfulRow)
+    .map((str) => str.split('\t').map((cell) => cell.trim()))
+  const headers = rows.length ? rows[0] : []
+
+  headers.forEach((x) => {
+    columns.set(x, [])
+  })
+  for (let i = 1; i < rows.length; i++) {
+    for (let j = 0; j < headers.length; j++) {
+      columns.get(headers[j])?.push(rows[i][j])
+    }
+  }
+  for (const [key, value] of columns) {
+    columns.set(key, value)
+  }
+  return columns
+}
+/**
+ * Convert parsed TSV file data from the old BIDS format to the new BIDS format.
+ *
+ * @param {{headers: string[], rows: string[][]}} oldParsedTsv Parsed TSV data using the old format
+ * @returns {Map[]} The parsed contents of the TSV file, using the new format.
+ */
+export function convertParsedTSVData(oldParsedTsv) {
+  const columns = new Map()
+
+  oldParsedTsv.headers.forEach((x) => {
+    columns.set(x, [])
+  })
+  for (let i = 1; i < oldParsedTsv.rows.length; i++) {
+    for (let j = 0; j < oldParsedTsv.headers.length; j++) {
+      columns.get(oldParsedTsv.headers[j])?.push(oldParsedTsv.rows[i][j])
+    }
+  }
+  for (const [key, value] of columns) {
+    columns.set(key, value)
+  }
+  return columns
+}
+
+export default parseTSV
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_types_dataset.js.html b/docs/html/bids_types_dataset.js.html new file mode 100644 index 00000000..72eb3020 --- /dev/null +++ b/docs/html/bids_types_dataset.js.html @@ -0,0 +1,210 @@ + + + + + JSDoc: Source: bids/types/dataset.js + + + + + + + + + +
+

Source: bids/types/dataset.js

+ +
+
+
export class BidsDataset {
+  /**
+   * The dataset's event file data.
+   * @type {BidsTsvFile[]}
+   */
+  eventData
+  /**
+   * The dataset's bidsFile data.
+   * @type {BidsSidecar[]}
+   */
+  sidecarData
+  /**
+   * The dataset's dataset_description.json file.
+   * @type {BidsJsonFile}
+   */
+  datasetDescription
+  /**
+   * The dataset's root directory as an absolute path.
+   * @type {string|null}
+   */
+  datasetRootDirectory
+
+  constructor(eventData, sidecarData, datasetDescription, datasetRootDirectory = null) {
+    this.eventData = eventData
+    this.sidecarData = sidecarData
+    this.datasetDescription = datasetDescription
+    this.datasetRootDirectory = datasetRootDirectory
+  }
+
+  get hasHedData() {
+    return (
+      this.sidecarData.some((sidecarFileData) => sidecarFileData.hasHedData()) ||
+      this.eventData.some((tsvFileData) => tsvFileData.hasHedData())
+    )
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_types_file.js.html b/docs/html/bids_types_file.js.html new file mode 100644 index 00000000..92f016fb --- /dev/null +++ b/docs/html/bids_types_file.js.html @@ -0,0 +1,252 @@ + + + + + JSDoc: Source: bids/types/file.js + + + + + + + + + +
+

Source: bids/types/file.js

+ +
+
+
import { BidsHedIssue } from './issues'
+import { generateIssue } from '../../issues/issues'
+
+/**
+ * A BIDS file.
+ */
+export class BidsFile {
+  /**
+   * The name of this file.
+   * @type {string}
+   */
+  name
+  /**
+   * The file object representing this file data.
+   * This is used to generate {@link BidsIssue} objects.
+   * @type {object}
+   */
+  file
+  /**
+   * The validator class used to validate this file.
+   * @private
+   */
+  _validatorClass
+
+  /**
+   *
+   * @param {string} name - The name of the file -- used for messages.
+   * @param {object} file - The representation of the file for error messages.
+   * @param validatorClass
+   */
+  constructor(name, file, validatorClass) {
+    this.name = name
+    this.file = file
+    this._validatorClass = validatorClass
+  }
+
+  /**
+   * Determine whether this file has any HED data.
+   *
+   * @returns {boolean} - True if this file has HED data.
+   */
+  hasHedData() {
+    return false
+  }
+
+  /**
+   * Validate this validator's tsv file.
+   *
+   * @param {Schemas} schemas - The HED schemas used to validate this file.
+   * @returns {BidsIssue[]} - Any issues found during validation of this TSV file.
+   */
+  validate(schemas) {
+    if (!this.hasHedData()) {
+      return []
+    }
+    if (!schemas) {
+      BidsHedIssue.fromHedIssue(
+        generateIssue('genericError', {
+          message: 'BIDS file HED validation requires a HED schema, but the schema received was null.',
+        }),
+        { path: this.file.file, relativePath: this.file.file },
+      )
+    }
+
+    try {
+      const validator = new this.validatorClass(this, schemas)
+      return validator.validate()
+    } catch (internalError) {
+      return BidsHedIssue.fromHedIssues(internalError, this.file)
+    }
+  }
+
+  /**
+   * The validator class used to validate this file.
+   * @returns {*}
+   */
+  get validatorClass() {
+    return this._validatorClass
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_types_issues.js.html b/docs/html/bids_types_issues.js.html new file mode 100644 index 00000000..114629cd --- /dev/null +++ b/docs/html/bids_types_issues.js.html @@ -0,0 +1,293 @@ + + + + + JSDoc: Source: bids/types/issues.js + + + + + + + + + +
+

Source: bids/types/issues.js

+ +
+
+
import { generateIssue, IssueError } from '../../issues/issues'
+
+const bidsHedErrorCodes = new Set([104, 106, 107])
+
+export class BidsIssue {
+  /**
+   * The BIDS issue code.
+   * @type {number}
+   */
+  code
+  /**
+   * The file associated with this issue.
+   * @type {Object}
+   */
+  file
+  /**
+   * The evidence for this issue.
+   * @type {string}
+   */
+  evidence
+
+  constructor(issueCode, file, evidence) {
+    this.code = issueCode
+    this.file = file
+    this.evidence = evidence
+  }
+
+  /**
+   * Whether this issue is an error.
+   *
+   * @returns {boolean}
+   */
+  isError() {
+    return bidsHedErrorCodes.has(this.code)
+  }
+
+  /**
+   * Determine if any of the passed issues are errors.
+   *
+   * @param {BidsIssue[]} issues A list of issues.
+   * @returns {boolean} Whether any of the passed issues are errors (rather than warnings).
+   */
+  static anyAreErrors(issues) {
+    return issues.some((issue) => issue.isError())
+  }
+
+  static async generateInternalErrorPromise(error, errorFile) {
+    return [new BidsHedIssue(generateIssue('internalError', { message: error.message }), errorFile)]
+  }
+}
+
+export class BidsHedIssue extends BidsIssue {
+  /**
+   * The HED Issue object corresponding to this object.
+   * @type {Issue}
+   */
+  hedIssue
+
+  /**
+   * Constructor.
+   *
+   * @param {Issue} hedIssue The HED issue object to be wrapped.
+   * @param {Object} file The file this error occurred in.
+   */
+  constructor(hedIssue, file) {
+    super(BidsHedIssue._determineBidsIssueCode(hedIssue), file, hedIssue.message)
+
+    this.hedIssue = hedIssue
+  }
+
+  /**
+   * Determine the BIDS issue code for this issue.
+   *
+   * @param {Issue} hedIssue The HED issue object to be wrapped.
+   * @returns {number} The BIDS issue code for this issue.
+   * @private
+   */
+  static _determineBidsIssueCode(hedIssue) {
+    if (hedIssue.internalCode === 'internalError' || hedIssue.internalCode === 'internalConsistencyError') {
+      return 106
+    }
+    if (hedIssue.level === 'warning') {
+      return 105
+    }
+    return 104
+  }
+
+  /**
+   * Convert one or more HED issues into BIDS-compatible issues.
+   *
+   * @param {Error|Issue[]} hedIssues One or more HED-format issues.
+   * @param {Object} file A BIDS-format file object used to generate {@link BidsHedIssue} objects.
+   * @param {Object?} extraParameters Any extra parameters to inject into the {@link Issue} objects.
+   * @returns {BidsHedIssue[]} The passed issue(s) in BIDS-compatible format.
+   */
+  static fromHedIssues(hedIssues, file, extraParameters) {
+    if (hedIssues instanceof IssueError) {
+      return [BidsHedIssue.fromHedIssue(hedIssues.issue, file, extraParameters)]
+    } else if (hedIssues instanceof Error) {
+      return [new BidsHedIssue(generateIssue('internalError', { message: hedIssues.message }), file ?? null)]
+    } else {
+      return hedIssues.map((hedIssue) => BidsHedIssue.fromHedIssue(hedIssue, file, extraParameters))
+    }
+  }
+
+  /**
+   * Convert a single HED issue into a BIDS-compatible issue.
+   *
+   * @param {Issue} hedIssue One HED-format issue.
+   * @param {Object} file A BIDS-format file object used to generate a {@link BidsHedIssue} object.
+   * @param {Object?} extraParameters Any extra parameters to inject into the {@link Issue} object.
+   * @returns {BidsHedIssue} The passed issue in BIDS-compatible format.
+   */
+  static fromHedIssue(hedIssue, file, extraParameters) {
+    if (extraParameters) {
+      Object.assign(hedIssue.parameters, extraParameters)
+      hedIssue.generateMessage()
+    }
+    return new BidsHedIssue(hedIssue, file)
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_types_json.js.html b/docs/html/bids_types_json.js.html new file mode 100644 index 00000000..a2d0ac51 --- /dev/null +++ b/docs/html/bids_types_json.js.html @@ -0,0 +1,571 @@ + + + + + JSDoc: Source: bids/types/json.js + + + + + + + + + +
+

Source: bids/types/json.js

+ +
+
+
import isPlainObject from 'lodash/isPlainObject'
+
+import { sidecarValueHasHed } from '../utils'
+import { parseHedString } from '../../parser/parser'
+import ParsedHedString from '../../parser/parsedHedString'
+import { BidsFile } from './file'
+import BidsHedSidecarValidator from '../validator/sidecarValidator'
+import { IssueError } from '../../issues/issues'
+import { DefinitionManager, Definition } from '../../parser/definitionManager'
+
+const ILLEGAL_SIDECAR_KEYS = new Set(['hed', 'n/a'])
+
+/**
+ * A BIDS JSON file.
+ */
+export class BidsJsonFile extends BidsFile {
+  /**
+   * This file's JSON data.
+   * @type {object}
+   */
+  jsonData
+
+  constructor(name, jsonData, file) {
+    super(name, file, BidsHedSidecarValidator)
+    this.jsonData = jsonData
+  }
+}
+
+export class BidsSidecar extends BidsJsonFile {
+  /**
+   * The extracted keys for this bidsFile (string --> BidsSidecarKey)
+   * @type {Map}
+   */
+  sidecarKeys
+  /**
+   * The extracted HED data for this bidsFile (string --> string | Object: string, string
+   * @type {Map}
+   */
+  hedData
+  /**
+   * The parsed HED data for this bidsFile (string --> ParsedHedString | Map: string --> ParsedHedString
+   * @type {Map}
+   */
+  parsedHedData
+  /**
+   * The extracted HED value strings.
+   * @type {string[]}
+   */
+  hedValueStrings
+  /**
+   * The extracted HED categorical strings.
+   * @type {string[]}
+   */
+  hedCategoricalStrings
+  /**
+   * The mapping of column splice references (string --> Set of string)
+   * @type {Map}
+   */
+  columnSpliceMapping
+  /**
+   * The set of column splice references.
+   * @type {Set<string>}
+   */
+  columnSpliceReferences
+
+  /**
+   * The object that manages definitions
+   * @type {DefinitionManager}
+   */
+  definitions
+
+  /**
+   * Constructor.
+   *
+   * @param {string} name The name of the bidsFile file.
+   * @param {Object} sidecarData The raw JSON data.
+   * @param {Object} file The file object representing this file.
+   * @param {DefinitionManager } defManager - The external definitions to use
+   */
+  constructor(name, sidecarData = {}, file, defManager = null) {
+    super(name, sidecarData, file)
+    this.columnSpliceMapping = new Map()
+    this.columnSpliceReferences = new Set()
+    this._setDefinitions(defManager)
+    this._filterHedStrings()
+    this._categorizeHedStrings()
+  }
+
+  _setDefinitions(defManager) {
+    if (defManager instanceof DefinitionManager) {
+      this.definitions = defManager
+    } else if (!defManager) {
+      this.definitions = new DefinitionManager()
+    } else {
+      IssueError.generateAndThrow('internalError', {
+        message: 'Improper format for defManager parameter -- must be null or DefinitionManager',
+      })
+    }
+  }
+
+  /**
+   * Create the bidsFile key map from the JSON.
+   * @private
+   */
+  _filterHedStrings() {
+    this.sidecarKeys = new Map(
+      Object.entries(this.jsonData)
+        .map(([key, value]) => {
+          const trimmedKey = key.trim()
+          const lowerKey = trimmedKey.toLowerCase()
+
+          if (ILLEGAL_SIDECAR_KEYS.has(lowerKey)) {
+            IssueError.generateAndThrow('illegalSidecarHedKey')
+          }
+
+          if (sidecarValueHasHed(value)) {
+            return [trimmedKey, new BidsSidecarKey(trimmedKey, value.HED, this)]
+          }
+
+          this._verifyKeyHasNoDeepHed(key, value)
+          return null
+        })
+        .filter(Boolean),
+    )
+  }
+
+  /**
+   * Verify that a column has no deeply nested "HED" keys.
+   *
+   * @param {string} key An object key.
+   * @param {*} value An object value.
+   * @throws {IssueError} If an invalid "HED" key is found.
+   * @private
+   */
+  _verifyKeyHasNoDeepHed(key, value) {
+    if (key.toUpperCase() === 'HED') {
+      IssueError.generateAndThrow('illegalSidecarHedDeepKey')
+    }
+    if (!isPlainObject(value)) {
+      return
+    }
+    for (const [subkey, subvalue] of Object.entries(value)) {
+      this._verifyKeyHasNoDeepHed(subkey, subvalue)
+    }
+  }
+
+  /**
+   * Categorize the column strings into value strings and categorical strings
+   * @private
+   */
+  _categorizeHedStrings() {
+    this.hedValueStrings = []
+    this.hedCategoricalStrings = []
+    this.hedData = new Map()
+    for (const [key, sidecarValue] of this.sidecarKeys.entries()) {
+      if (sidecarValue.isValueKey) {
+        this.hedValueStrings.push(sidecarValue.valueString)
+        this.hedData.set(key, sidecarValue.valueString)
+      } else {
+        this.hedCategoricalStrings.push(...Object.values(sidecarValue.categoryMap))
+        this.hedData.set(key, sidecarValue.categoryMap)
+      }
+    }
+  }
+
+  /**
+   * Determine whether this file has any HED data.
+   *
+   * @returns {boolean}
+   */
+  hasHedData() {
+    return this.sidecarKeys.size > 0
+  }
+
+  /**
+   * Parse this bidsFile's HED strings within the bidsFile structure.
+   *
+   * The parsed strings are placed into {@link parsedHedData}.
+   *
+   * @param {Schemas} hedSchemas - The HED schema collection.
+   * @returns {Issue[]} Any issues found.
+   */
+  parseHedStrings(hedSchemas) {
+    this.parsedHedData = new Map()
+    const issues = []
+    for (const [name, sidecarKey] of this.sidecarKeys.entries()) {
+      issues.push(...sidecarKey.parseHed(hedSchemas))
+      if (sidecarKey.isValueKey) {
+        this.parsedHedData.set(name, sidecarKey.parsedValueString)
+      } else {
+        this.parsedHedData.set(name, sidecarKey.parsedCategoryMap)
+      }
+    }
+    this._generateSidecarColumnSpliceMap()
+    return issues
+  }
+
+  /**
+   * Generate a mapping of an individual BIDS bidsFile's curly brace references.
+   *
+   * @private
+   */
+  _generateSidecarColumnSpliceMap() {
+    this.columnSpliceMapping = new Map()
+    this.columnSpliceReferences = new Set()
+
+    for (const [sidecarKey, hedData] of this.parsedHedData) {
+      if (hedData instanceof ParsedHedString) {
+        this._parseValueSplice(sidecarKey, hedData)
+      } else if (hedData instanceof Map) {
+        this._parseCategorySplice(sidecarKey, hedData)
+      } else if (hedData) {
+        IssueError.generateAndThrow('internalConsistencyError', {
+          message: 'Unexpected type found in bidsFile parsedHedData map.',
+        })
+      }
+    }
+  }
+
+  _parseValueSplice(sidecarKey, hedData) {
+    if (hedData.columnSplices.length > 0) {
+      const keyReferences = this._processColumnSplices(new Set(), hedData.columnSplices)
+      this.columnSpliceMapping.set(sidecarKey, keyReferences)
+    }
+  }
+
+  _parseCategorySplice(sidecarKey, hedData) {
+    let keyReferences = null
+    for (const valueString of hedData.values()) {
+      if (valueString?.columnSplices.length > 0) {
+        keyReferences = this._processColumnSplices(keyReferences, valueString.columnSplices)
+      }
+    }
+    if (keyReferences instanceof Set) {
+      this.columnSpliceMapping.set(sidecarKey, keyReferences)
+    }
+  }
+
+  /**
+   * Add a list of columnSplices to a key map.
+   * @param {Set} keyReferences
+   * @param {ParsedHedColumnSplice[]} columnSplices
+   * @returns {*|Set<any>}
+   * @private
+   */
+  _processColumnSplices(keyReferences, columnSplices) {
+    keyReferences ??= new Set()
+    for (const columnSplice of columnSplices) {
+      keyReferences.add(columnSplice.originalTag)
+      this.columnSpliceReferences.add(columnSplice.originalTag)
+    }
+    return keyReferences
+  }
+
+  /**
+   * The extracted HED strings.
+   * @returns {string[]}
+   */
+  get hedStrings() {
+    return this.hedValueStrings.concat(this.hedCategoricalStrings)
+  }
+}
+
+export class BidsSidecarKey {
+  /**
+   * The name of this key.
+   * @type {string}
+   */
+  name
+  /**
+   * The unparsed category mapping.
+   * @type {Object<string, string>}
+   */
+  categoryMap
+  /**
+   * The parsed category mapping.
+   * @type {Map<string, ParsedHedString>}
+   */
+  parsedCategoryMap
+  /**
+   * The unparsed value string.
+   * @type {string}
+   */
+  valueString
+  /**
+   * The parsed value string.
+   * @type {ParsedHedString}
+   */
+  parsedValueString
+  /**
+   * Weak reference to the bidsFile.
+   * @type {BidsSidecar}
+   */
+  sidecar
+
+  hasDefinitions
+
+  /**
+   * Constructor.
+   *
+   * @param {string} key The name of this key.
+   * @param {string|Object<string, string>} data The data for this key.
+   * @param {BidsSidecar} sidecar The parent bidsFile.
+   */
+  constructor(key, data, sidecar) {
+    this.name = key
+    this.hasDefinitions = false // May reset to true when definitions for this key are checked
+    this.sidecar = sidecar
+    if (typeof data === 'string') {
+      this.valueString = data
+    } else if (!isPlainObject(data)) {
+      IssueError.generateAndThrow('illegalSidecarHedType', { key: key, file: sidecar.file.relativePath })
+    } else {
+      this.categoryMap = data
+    }
+  }
+
+  /**
+   * Parse the HED data for this key.
+   *
+   * @param {Schemas} hedSchemas The HED schema collection.
+   * @returns {Issue[]} Any issues found.
+   */
+  parseHed(hedSchemas) {
+    if (this.isValueKey) {
+      return this._parseValueString(hedSchemas)
+    }
+    return this._parseCategory(hedSchemas)
+  }
+
+  /**
+   * Parse the value string in a bidsFile
+   * @param {Schemas} hedSchemas - The HED schemas to use.
+   * @returns {Issue[]}
+   * @private
+   *
+   * ### Note:
+   *  The value strings cannot contain definitions.
+   */
+  _parseValueString(hedSchemas) {
+    const [parsedString, parsingIssues] = parseHedString(this.valueString, hedSchemas, false, true)
+    this.parsedValueString = parsedString
+    return parsingIssues
+  }
+
+  /**
+   * Parse the categorical values associated with this key.
+   * @param {Schemas} hedSchemas - The HED schemas used to check against.
+   * @returns {Issue[]} - A list of issues if any
+   * @private
+   */
+  _parseCategory(hedSchemas) {
+    const issues = []
+    this.parsedCategoryMap = new Map()
+    for (const [value, string] of Object.entries(this.categoryMap)) {
+      const trimmedValue = value.trim()
+      if (ILLEGAL_SIDECAR_KEYS.has(trimmedValue.toLowerCase())) {
+        IssueError.generateAndThrow('illegalSidecarHedCategoricalValue')
+      } else if (typeof string !== 'string') {
+        IssueError.generateAndThrow('illegalSidecarHedType', {
+          key: value,
+          file: this.sidecar?.file?.relativePath,
+        })
+      }
+      const [parsedString, parsingIssues] = parseHedString(string, hedSchemas, true, true)
+      this.parsedCategoryMap.set(value, parsedString)
+      issues.push(...parsingIssues)
+      if (parsingIssues.length === 0) {
+        issues.push(...this._checkDefinitions(parsedString))
+      }
+    }
+    return issues
+  }
+
+  _checkDefinitions(parsedString) {
+    const issues = []
+    for (const group of parsedString.tagGroups) {
+      if (!group.isDefinitionGroup) {
+        continue
+      }
+      this.hasDefinitions = true
+      const [def, defIssues] = Definition.createDefinitionFromGroup(group)
+      if (defIssues.length > 0) {
+        issues.push(...defIssues)
+      } else {
+        issues.push(...this.sidecar.definitions.addDefinition(def))
+      }
+    }
+    return issues
+  }
+
+  /**
+   * Whether this key is a value key.
+   * @returns {boolean}
+   */
+  get isValueKey() {
+    return Boolean(this.valueString)
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_types_tsv.js.html b/docs/html/bids_types_tsv.js.html new file mode 100644 index 00000000..8f12e241 --- /dev/null +++ b/docs/html/bids_types_tsv.js.html @@ -0,0 +1,356 @@ + + + + + JSDoc: Source: bids/types/tsv.js + + + + + + + + + +
+

Source: bids/types/tsv.js

+ +
+
+
import isPlainObject from 'lodash/isPlainObject'
+
+import { BidsFile } from './file'
+import { convertParsedTSVData, parseTSV } from '../tsvParser'
+import { BidsSidecar } from './json'
+import BidsHedTsvValidator from '../validator/tsvValidator'
+import { IssueError } from '../../issues/issues'
+
+/**
+ * A BIDS TSV file.
+ */
+export class BidsTsvFile extends BidsFile {
+  /**
+   * This file's parsed TSV data.
+   * @type {Map[]}
+   */
+  parsedTsv
+  /**
+   * HED strings in the "HED" column of the TSV data.
+   * @type {string[]}
+   */
+  hedColumnHedStrings
+  /**
+   * The list of potential JSON sidecars.
+   * @type {string[]}
+   */
+  potentialSidecars
+  /**
+   * The pseudo-bidsFile object representing the merged bidsFile data.
+   * @type {BidsSidecar}
+   */
+  mergedSidecar
+
+  /**
+   * Constructor.
+   *
+   * @todo This interface is provisional and subject to modification in version 4.0.0.
+   *
+   * @param {string} name The name of the TSV file.
+   * @param {{headers: string[], rows: string[][]|Map[]|string} tsvData This file's TSV data.
+   * @param {object} file The file object representing this file.
+   * @param {string[]} potentialSidecars The list of potential JSON sidecars.
+   * @param {object} mergedDictionary The merged bidsFile data.
+   * @param {DefinitionManager} defManager
+   */
+  constructor(name, tsvData, file, potentialSidecars = [], mergedDictionary = {}, defManager) {
+    super(name, file, BidsHedTsvValidator)
+
+    if (typeof tsvData === 'string') {
+      this.parsedTsv = parseTSV(tsvData)
+    } else if (tsvData instanceof Map) {
+      this.parsedTsv = tsvData
+    } else if (isPlainObject(tsvData)) {
+      this.parsedTsv = convertParsedTSVData(tsvData)
+    } else {
+      IssueError.generateAndThrow('internalError', { message: 'parsedTsv has an invalid type' })
+    }
+
+    this.potentialSidecars = potentialSidecars
+    this.mergedSidecar = new BidsSidecar(name, mergedDictionary, this.file, defManager)
+    this._parseHedColumn()
+  }
+
+  _parseHedColumn() {
+    const hedColumn = this.parsedTsv.get('HED')
+    if (hedColumn === undefined) {
+      this.hedColumnHedStrings = []
+    } else {
+      this.hedColumnHedStrings = hedColumn.map((hedCell) => (hedCell && hedCell !== 'n/a' ? hedCell : ''))
+    }
+  }
+
+  /**
+   * Determine whether this file has any HED data.
+   *
+   * @todo To be replaced with property in version 4.0.0.
+   *
+   * @returns {boolean}
+   */
+  hasHedData() {
+    return this.parsedTsv.has('HED') || this.mergedSidecar.hasHedData()
+  }
+
+  /**
+   * Whether this TSV file is a timeline file.
+   *
+   * @returns {boolean}
+   */
+  get isTimelineFile() {
+    return this.parsedTsv.has('onset')
+  }
+}
+
+export class BidsTsvElement {
+  /**
+   * The string representation of this row
+   * @type {string}
+   */
+  hedString
+
+  /**
+   * The ParsedHedString representation of this row
+   * @type {ParsedHedString}
+   */
+  parsedHedString
+
+  /**
+   * The file this row belongs to (usually just the path).
+   * @type {Object}
+   */
+  file
+
+  /**
+   * The onset represented by this row or a NaN.
+   * @type {Number}
+   */
+  onset
+
+  /**
+   * The line number(s) (including the header) represented by this row.
+   */
+  tsvLine
+
+  /**
+   * Constructor.
+   *
+   * @param {string} hedString The HED string representing this row
+   * @param {BidsTsvFile} tsvFile The file this row belongs to.
+   * @param {number} onset - The onset for this element or undefined if none
+   * @param {string} tsvLine The line number(s) (string) corresponding to the lines in {@link tsvFile} this line is located at.
+   */
+  constructor(hedString, tsvFile, onset, tsvLine) {
+    this.hedString = hedString
+    this.parsedHedString = null
+    this.file = tsvFile.file
+    this.fileName = tsvFile.name
+    this.onset = onset
+    this.tsvLine = tsvLine
+  }
+
+  /**
+   * Override of {@link Object.prototype.toString}.
+   *
+   * @returns {string}
+   */
+  toString() {
+    const onsetString = this.onset ? ` with onset=${this.onset.toString()}` : ''
+    return this.hedString + ` in TSV file "${this.fileName}" at line(s) ${this.tsvLine}` + onsetString
+  }
+
+  /**
+   * Create a string list of a list of BidsTsvElement objects.
+   * @param BidsTsvElement[] elements - A list of elements to construct line numbers from.
+   * @returns {string} - A string with the list of line numbers for error messages.
+   */
+  static getTsvLines(elements) {
+    return elements.map((element) => element.tsvLine).join(',')
+  }
+}
+
+/**
+ * A row in a BIDS TSV file.
+ */
+export class BidsTsvRow extends BidsTsvElement {
+  /**
+   * The map of column name to value for this row.
+   * @type {Map}
+   */
+  rowCells
+
+  /**
+   * Constructor.
+   *
+   * @param {string} hedString The parsed string representing this row.
+   * @param {Map} rowCells The column-to-value mapping for this row.
+   * @param {BidsTsvFile} tsvFile The file this row belongs to.
+   * @param {number} tsvLine The line number in {@link tsvFile} this line is located at.
+   */
+  constructor(hedString, tsvFile, tsvLine, rowCells) {
+    const onset = rowCells.has('onset') ? rowCells.get('onset') : undefined
+    super(hedString, tsvFile, onset, tsvLine.toString())
+    this.rowCells = rowCells
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_utils.js.html b/docs/html/bids_utils.js.html new file mode 100644 index 00000000..341ca760 --- /dev/null +++ b/docs/html/bids_utils.js.html @@ -0,0 +1,181 @@ + + + + + JSDoc: Source: bids/utils.js + + + + + + + + + +
+

Source: bids/utils.js

+ +
+
+
/**
+ * Determine whether a bidsFile value has HED data.
+ *
+ * @param {object} sidecarValue A BIDS bidsFile value.
+ * @returns {boolean} Whether the bidsFile value has HED data.
+ */
+export const sidecarValueHasHed = function (sidecarValue) {
+  return sidecarValue !== null && typeof sidecarValue === 'object' && sidecarValue.HED !== undefined
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_validate.js.html b/docs/html/bids_validate.js.html new file mode 100644 index 00000000..b28ce8c7 --- /dev/null +++ b/docs/html/bids_validate.js.html @@ -0,0 +1,309 @@ + + + + + JSDoc: Source: bids/validate.js + + + + + + + + + +
+

Source: bids/validate.js

+ +
+
+
import { buildBidsSchemas } from './schema'
+import { BidsHedIssue, BidsIssue } from './types/issues'
+import { generateIssue } from '../issues/issues'
+
+/**
+ * Validate a BIDS dataset.
+ *
+ * @param {BidsDataset} dataset The BIDS dataset.
+ * @param {SchemasSpec} schemaDefinition The version spec for the schema to be loaded.
+ * @returns {Promise} A promise for list of Any issues found.
+ */
+export async function validateBidsDataset(dataset, schemaDefinition) {
+  const validator = new BidsHedValidator(dataset, schemaDefinition)
+  return validator.validate()
+}
+
+export default validateBidsDataset
+
+/**
+ * A validator for HED content in a BIDS dataset.
+ */
+class BidsHedValidator {
+  /**
+   * The BIDS dataset being validated.
+   * @type {BidsDataset}
+   */
+  dataset
+  /**
+   * The schema specification override.
+   * @type {SchemasSpec}
+   */
+  schemaDefinition
+  /**
+   * The HED schema collection being validated against.
+   * @type {Schemas}
+   */
+  hedSchemas
+  /**
+   * The issues found during validation.
+   * @type {BidsIssue[]}
+   */
+  issues
+
+  /**
+   * Constructor.
+   *
+   * @param {BidsDataset} dataset The BIDS dataset being validated.
+   * @param {SchemasSpec} schemaDefinition The version spec for the schema to be loaded.
+   */
+  constructor(dataset, schemaDefinition) {
+    this.dataset = dataset
+    this.schemaDefinition = schemaDefinition
+    this.issues = []
+  }
+
+  async validate() {
+    this.issues.push(...(await this._buildSchemas()))
+    if (this.issues.length > 0) {
+      return this.issues
+    }
+    try {
+      this.validateFullDataset()
+    } catch (internalError) {
+      return BidsIssue.generateInternalErrorPromise(internalError, this.dataset.datasetDescription.file)
+    }
+    return this.issues
+  }
+
+  async _buildSchemas() {
+    try {
+      this.hedSchemas = await buildBidsSchemas(this.dataset.datasetDescription, this.schemaDefinition)
+      if (this.hedSchemas === null && this.dataset.hasHedData) {
+        return [
+          BidsHedIssue.fromHedIssue(
+            generateIssue('missingSchemaSpecification', {}),
+            this.dataset.datasetDescription.file,
+          ),
+        ]
+      }
+      return []
+    } catch (schemaIssues) {
+      return BidsHedIssue.fromHedIssues(schemaIssues, this.dataset.datasetDescription.file)
+    }
+  }
+
+  /**
+   * Validate a full BIDS dataset using a HED schema collection.
+   *
+   * @returns {BidsIssue[]} Any issues found.
+   */
+  validateFullDataset() {
+    this._validateFiles(this.dataset.sidecarData)
+    if (BidsIssue.anyAreErrors(this.issues)) {
+      return this.issues
+    }
+    this._validateFiles(this.dataset.eventData)
+    return this.issues
+  }
+
+  /**
+   * Validate a set of BIDS files using a HED schema collection.
+   *
+   * @param {BidsFile[]} files The list of files.
+   * @private
+   */
+  _validateFiles(files) {
+    for (const file of files) {
+      const schemaFound = this._validateFile(file)
+      if (!schemaFound) {
+        return
+      }
+    }
+  }
+
+  /**
+   * Validate a BIDS file using a HED schema collection.
+   *
+   * @returns {boolean} If the schema was found by the validator.
+   * @private
+   */
+  _validateFile(file) {
+    const issues = file.validate(this.hedSchemas)
+    if (issues === null) {
+      this.issues.push(
+        BidsHedIssue.fromHedIssue(
+          generateIssue('missingSchemaSpecification', {}),
+          this.dataset.datasetDescription.file,
+        ),
+      )
+      return false
+    }
+    this.issues.push(...issues)
+    return true
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_validator_sidecarValidator.js.html b/docs/html/bids_validator_sidecarValidator.js.html new file mode 100644 index 00000000..07e541d9 --- /dev/null +++ b/docs/html/bids_validator_sidecarValidator.js.html @@ -0,0 +1,333 @@ + + + + + JSDoc: Source: bids/validator/sidecarValidator.js + + + + + + + + + +
+

Source: bids/validator/sidecarValidator.js

+ +
+
+
import { BidsHedIssue } from '../types/issues'
+import ParsedHedString from '../../parser/parsedHedString'
+import { generateIssue, IssueError } from '../../issues/issues'
+import { getCharacterCount } from '../../utils/string.js'
+import { BidsValidator } from './validator'
+
+/**
+ * Validator for HED data in BIDS JSON sidecars.
+ */
+export class BidsHedSidecarValidator extends BidsValidator {
+  /**
+   * Constructor for the BidsHedSidecarValidator.
+   *
+   * @param {BidsSidecar} sidecar - The BIDS bidsFile being validated.
+   * @param {Schemas} hedSchemas - The schemas used for the sidecar validation.
+   */
+  constructor(sidecar, hedSchemas) {
+    super(sidecar, hedSchemas)
+  }
+
+  /**
+   * Validate a BIDS JSON bidsFile file. This method returns the complete issue list for convenience.
+   *
+   * @returns {BidsIssue[]} - Any issues found during validation of this bidsFile file.
+   */
+  validate() {
+    // Allow schema to be set a validation time -- this is checked by the superclass of BIDS file
+    const sidecarParsingIssues = BidsHedIssue.fromHedIssues(
+      this.bidsFile.parseHedStrings(this.hedSchemas),
+      this.bidsFile.file,
+    )
+    this.issues.push(...sidecarParsingIssues)
+    if (sidecarParsingIssues.length > 0) {
+      return this.issues
+    }
+    this.issues.push(...this._validateStrings(), ...this._validateCurlyBraces())
+    return this.issues
+  }
+
+  /**
+   * Validate this bidsFile's HED strings.
+   *
+   * @returns {BidsIssue[]} All issues found.
+   */
+  _validateStrings() {
+    const issues = []
+
+    for (const [sidecarKeyName, hedData] of this.bidsFile.parsedHedData) {
+      if (hedData instanceof ParsedHedString) {
+        // Value options have HED as string.
+        issues.push(...this._checkDetails(sidecarKeyName, hedData))
+      } else if (hedData instanceof Map) {
+        // Categorical options have HED as a Map.
+        for (const valueString of hedData.values()) {
+          issues.push(...this._checkDetails(sidecarKeyName, valueString))
+        }
+      } else {
+        IssueError.generateAndThrow('internalConsistencyError', {
+          message: 'Unexpected type found in bidsFile parsedHedData map.',
+        })
+      }
+    }
+    return issues
+  }
+
+  /**
+   * Check definitions and placeholders for a string associated with a sidecar key.
+   *
+   * @param {string} sidecarKeyName - The name of the sidecar key associated with string to be checked.
+   * @param {ParsedHedString} hedString - The parsed string to be checked.
+   * @returns {BidsHedIssue[]} - Issues associated with the check.
+   * @private
+   */
+  _checkDetails(sidecarKeyName, hedString) {
+    const issues = this._checkDefs(sidecarKeyName, hedString, true)
+    issues.push(...this._checkPlaceholders(sidecarKeyName, hedString))
+    return issues
+  }
+
+  /**
+   * Validate the Def and Def-expand usage against the sidecar definitions.
+   *
+   * @param {string} sidecarKeyName - Name of the sidecar key for this HED string
+   * @param {ParsedHedString} hedString - The parsed HED string object associated with this key.
+   * @param {boolean} placeholdersAllowed - If true, placeholders are allowed here.
+   * @returns {BidsHedIssue[]} - Issues encountered such as missing definitions or improper Def-expand values.
+   * @private
+   */
+  _checkDefs(sidecarKeyName, hedString, placeholdersAllowed) {
+    let issues = this.bidsFile.definitions.validateDefs(hedString, this.hedSchemas, placeholdersAllowed)
+    if (issues.length > 0) {
+      return BidsHedIssue.fromHedIssues(issues, this.bidsFile.file, { sidecarKeyName: sidecarKeyName })
+    }
+    issues = this.bidsFile.definitions.validateDefExpands(hedString, this.hedSchemas, placeholdersAllowed)
+    return BidsHedIssue.fromHedIssues(issues, this.bidsFile.file, { sidecarKeyName: sidecarKeyName })
+  }
+
+  _checkPlaceholders(sidecarKeyName, hedString) {
+    const numberPlaceholders = getCharacterCount(hedString.hedString, '#')
+    const sidecarKey = this.bidsFile.sidecarKeys.get(sidecarKeyName)
+    if (!sidecarKey.valueString && !sidecarKey.hasDefinitions && numberPlaceholders > 0) {
+      return [
+        BidsHedIssue.fromHedIssue(
+          generateIssue('invalidSidecarPlaceholder', { column: sidecarKeyName, string: hedString.hedString }),
+          this.bidsFile.file,
+        ),
+      ]
+    } else if (sidecarKey.valueString && numberPlaceholders === 0) {
+      return [
+        BidsHedIssue.fromHedIssue(
+          generateIssue('missingPlaceholder', { column: sidecarKeyName, string: hedString.hedString }),
+          this.bidsFile.file,
+        ),
+      ]
+    }
+    if (sidecarKey.valueString && numberPlaceholders > 1) {
+      return [
+        BidsHedIssue.fromHedIssue(
+          generateIssue('invalidSidecarPlaceholder', { column: sidecarKeyName, string: hedString.hedString }),
+          this.bidsFile.file,
+        ),
+      ]
+    }
+    return []
+  }
+
+  /**
+   * Validate this bidsFile's curly braces -- checking recursion and missing columns.
+   *
+   * @returns {BidsIssue[]} All issues found.
+   */
+  _validateCurlyBraces() {
+    const issues = []
+    const references = this.bidsFile.columnSpliceMapping
+
+    for (const [key, referredKeys] of references) {
+      for (const referredKey of referredKeys) {
+        if (references.has(referredKey)) {
+          issues.push(
+            BidsHedIssue.fromHedIssue(
+              generateIssue('recursiveCurlyBracesWithKey', { column: referredKey, referrer: key }),
+              this.bidsFile.file,
+            ),
+          )
+        }
+        if (!this.bidsFile.parsedHedData.has(referredKey) && referredKey !== 'HED') {
+          issues.push(
+            BidsHedIssue.fromHedIssue(
+              generateIssue('undefinedCurlyBraces', { column: referredKey }),
+              this.bidsFile.file,
+            ),
+          )
+        }
+      }
+    }
+
+    return issues
+  }
+}
+
+export default BidsHedSidecarValidator
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_validator_tsvValidator.js.html b/docs/html/bids_validator_tsvValidator.js.html new file mode 100644 index 00000000..faa03a45 --- /dev/null +++ b/docs/html/bids_validator_tsvValidator.js.html @@ -0,0 +1,676 @@ + + + + + JSDoc: Source: bids/validator/tsvValidator.js + + + + + + + + + +
+

Source: bids/validator/tsvValidator.js

+ +
+
+
import { BidsHedIssue, BidsIssue } from '../types/issues'
+import { BidsTsvElement, BidsTsvRow } from '../types/tsv'
+import { BidsValidator } from './validator'
+import { parseHedString } from '../../parser/parser'
+import ParsedHedString from '../../parser/parsedHedString'
+import { generateIssue } from '../../issues/issues'
+import { ReservedChecker } from '../../parser/reservedChecker'
+import { getTagListString } from '../../parser/parseUtils'
+import { EventManager } from '../../parser/eventManager'
+
+/**
+ * Validator for HED data in BIDS TSV files.
+ */
+export class BidsHedTsvValidator extends BidsValidator {
+  /**
+   * The BIDS TSV file being validated.
+   * @type {ReservedChecker}
+   */
+  reserved
+
+  /**
+   * Constructor.
+   *
+   * @param {BidsTsvFile} tsvFile - The BIDS TSV file being validated.
+   * @param {Schemas} hedSchemas - The HED schemas used to validate the tsv file.
+   */
+  constructor(tsvFile, hedSchemas) {
+    super(tsvFile, hedSchemas)
+    this.reserved = ReservedChecker.getInstance()
+  }
+
+  /**
+   * Validate a BIDS TSV file. This method returns the complete issue list for convenience.
+   *
+   * @returns {BidsIssue[]} - Any issues found during validation of this TSV file.
+   */
+  validate() {
+    // Validate the BIDS bidsFile if it exists.
+    if (this.bidsFile.mergedSidecar) {
+      const sidecarIssues = this.bidsFile.mergedSidecar.validate(this.hedSchemas)
+      this.issues.push(...sidecarIssues)
+      if (BidsIssue.anyAreErrors(sidecarIssues)) {
+        return this.issues
+      }
+    }
+
+    // Valid the HED column by itself.
+    const hedColumnIssues = this._validateHedColumn()
+    this.issues.push(...hedColumnIssues)
+    if (BidsIssue.anyAreErrors(this.issues)) {
+      return this.issues
+    }
+    // Now do a full validation
+    const bidsHedTsvParser = new BidsHedTsvParser(this.bidsFile, this.hedSchemas)
+    const [bidsEvents, parsingIssues] = bidsHedTsvParser.parse()
+    this.issues.push(...parsingIssues)
+    if (!BidsIssue.anyAreErrors(this.issues)) {
+      this.issues.push(...this.validateDataset(bidsEvents))
+    }
+    return this.issues
+  }
+
+  /**
+   * Validate this TSV file's HED column.
+   *
+   * @returns {BidsIssue[]} - Issues found in validating the HED column without sidecar information.
+   * @private
+   */
+  _validateHedColumn() {
+    if (this.bidsFile.hedColumnHedStrings.length === 0) {
+      return []
+    }
+    return this.bidsFile.hedColumnHedStrings.flatMap((hedString, rowIndexMinusTwo) =>
+      this._validateHedColumnString(hedString, rowIndexMinusTwo + 2),
+    )
+  }
+
+  /**
+   * Validate a string in this TSV file's HED column.
+   *
+   * @param {string} hedString - The string to be validated.
+   * @param {number} rowIndex - The index of this row in the TSV file.
+   * @returns {BidsIssue[]} - Specific issues found in validating the HED column
+   * @private
+   */
+  _validateHedColumnString(hedString, rowIndex) {
+    if (!hedString) {
+      return []
+    }
+
+    // Find basic parsing issues and return if unable to parse the string. (Warnings are okay.)
+    const issues = []
+    const [parsedString, parsingIssues] = parseHedString(hedString, this.hedSchemas, false, false)
+    issues.push(...BidsHedIssue.fromHedIssues(parsingIssues, this.bidsFile.file, { tsvLine: rowIndex }))
+    if (parsedString === null) {
+      return issues
+    }
+
+    // The HED column is not allowed to have column splices.
+    if (parsedString.columnSplices.length > 0) {
+      issues.push(
+        BidsHedIssue.fromHedIssue(
+          generateIssue('curlyBracesInHedColumn', {
+            string: parsedString.hedString,
+            tsvLine: rowIndex.toString(),
+          }),
+          this.bidsFile.file,
+        ),
+      )
+      return issues
+    }
+
+    // Check whether definitions used exist and are used correctly.
+    const defIssues = [
+      ...this.bidsFile.mergedSidecar.definitions.validateDefs(parsedString, this.hedSchemas, false),
+      ...this.bidsFile.mergedSidecar.definitions.validateDefExpands(parsedString, this.hedSchemas, false),
+    ]
+    const convertedIssues = BidsHedIssue.fromHedIssues(defIssues, this.bidsFile.file, { tsvLine: rowIndex })
+    issues.push(...convertedIssues)
+    return issues
+  }
+
+  /**
+   * Validate the HED data in a combined event TSV file/bidsFile BIDS data collection.
+   *
+   * @param {BidsTsvElement[]} elements - The element objects, which include the strings and row information.
+   * @returns {BidsHedIssue[]} - The errors resulting from final validation, including dataset-level checks.
+   */
+  validateDataset(elements) {
+    // Final top-tag detection cannot be done until the strings are fully assembled and finalized.
+    const issues = this._checkNoTopTags(elements)
+    if (issues.length > 0) {
+      return issues
+    }
+    // Temporal files have to check Onset, Inset, Offset consistency.
+    if (this.bidsFile.isTimelineFile) {
+      return this._validateTemporal(elements)
+    }
+    // Non-temporal files cannot have temporal tags.
+    return this._checkNoTime(elements)
+  }
+
+  /**
+   * Check the temporal relationships among events.
+   *
+   * @param {BidsTsvElement[]} elements - The elements representing the tsv file.
+   * @returns {BidsHedIssue[]} - Errors in temporal relationships among events.
+   * @private
+   */
+  _validateTemporal(elements) {
+    // Check basic temporal conflicts such as Offset before Onset, or temporal tags with same def at same time.
+    const eventManager = new EventManager()
+    const [eventList, temporalIssues] = eventManager.parseEvents(elements)
+    if (temporalIssues.length > 0) {
+      return temporalIssues
+    }
+    // There still may be non-temporal duplicates when multiple rows with the same onset.
+    const duplicateErrors = this._checkDuplicatesAcrossRows(elements)
+    if (duplicateErrors.length > 0) {
+      return duplicateErrors
+    }
+    return eventManager.validate(eventList)
+  }
+
+  /**
+   * Check for duplicate tags when multiple rows with the same onset.
+   *
+   * @param {BidsTsvElement[]} elements - The elements representing the tsv file.
+   * @returns {BidsHedIssue[]} - Errors in temporal relationships among events.
+   * @private
+   *
+   * ### Note:
+   * Duplicate onsets are relatively rare and duplicates for single rows are checked when a ParsedHedString is
+   * constructed.
+   */
+  _checkDuplicatesAcrossRows(elements) {
+    const duplicateMap = this._getOnsetMap(elements)
+    const issues = []
+    for (const elementList of duplicateMap.values()) {
+      if (elementList.length === 1) {
+        continue
+      }
+      // Assemble the HED strings associated with same onset into single string. Use the parse duplicate detection.
+      const rowString = elementList.map((element) => element.hedString).join(',')
+      const [parsedString, parsingIssues] = parseHedString(rowString, this.hedSchemas, false, false)
+      if (parsingIssues.length > 0) {
+        const tsvLines = BidsTsvElement.getTsvLines(elementList)
+        issues.push(...BidsHedIssue.fromHedIssues(parsingIssues, this.bidsFile.file, { tsvLine: tsvLines }))
+      }
+    }
+    return issues
+  }
+
+  /**
+   * Get map of onsets to BidsTsvElements.
+   *
+   * @param {BidsTsvElement[]} elements - The elements representing the tsv file.
+   * @returns {Map} - Map of onset value to a list of elements with that onset.
+   * @private
+   */
+  _getOnsetMap(elements) {
+    const onsetMap = new Map()
+    for (const element of elements) {
+      if (!element.hedString) {
+        continue
+      }
+      if (onsetMap.has(element.onset)) {
+        onsetMap.get(element.onset).push(element)
+      } else {
+        onsetMap.set(element.onset, [element])
+      }
+    }
+    return onsetMap
+  }
+
+  /**
+   * Top group tag requirements may not be satisfied until all splices have been done.
+   *
+   * @param {BidsTsvElement[]} elements - The elements to be checked.
+   * @returns {BidsHedIssue[]} - Issues from final check of top groups.
+   * @private
+   */
+  _checkNoTopTags(elements) {
+    const topGroupIssues = []
+    for (const element of elements) {
+      const topTags = element.parsedHedString ? element.parsedHedString.topLevelTags : []
+      const badTags = topTags.filter((tag) => ReservedChecker.hasTopLevelTagGroupAttribute(tag))
+      if (badTags.length > 0) {
+        topGroupIssues.push(
+          BidsHedIssue.fromHedIssue(
+            generateIssue('invalidTopLevelTag', { tag: getTagListString(badTags), string: element.hedString }),
+            element.file,
+            { tsvLine: element.tsvLine },
+          ),
+        )
+      }
+    }
+    return topGroupIssues
+  }
+
+  /**
+   * Verify that this non-temporal file does not contain any temporal tags.
+   *
+   * @param {BidsTsvElement[]} elements - The elements representing a tsv file (with HED string parsed).
+   * @returns {BidsHedIssue[]} - Issues from checking non-temporal files for temporal tags.
+   */
+  _checkNoTime(elements) {
+    const timeIssues = []
+    for (const element of elements) {
+      if (element.parsedHedString.tags.some((tag) => this.reserved.timelineTags.has(tag.schemaTag.name))) {
+        timeIssues.push(
+          BidsHedIssue.fromHedIssue(
+            generateIssue('temporalTagInNonTemporalContext', { string: element.hedString, tsvLine: element.tsvLine }),
+            this.bidsFile.file,
+          ),
+        )
+      }
+    }
+    return timeIssues
+  }
+}
+
+/**
+ * Class that performs basic parsing and splicing.
+ */
+export class BidsHedTsvParser {
+  static nullSet = new Set([null, undefined, '', 'n/a'])
+  static braceRegEx = /\{([^{}]*?)\}/g
+  static parenthesesRegEx = /\(\s*[,\s]*(\(\s*[,\s]*\))*[,\s]*\)/g
+  static internalCommaRegEx = /,\s*,/g
+  static leadingCommaRegEx = /^\s*,+\s*/
+  static trailingCommaRegEx = /\s*,+\s*$/
+  /**
+   * The BIDS TSV file being parsed.
+   * @type {BidsTsvFile}
+   */
+  tsvFile
+  /**
+   * The HED schema collection being parsed against.
+   * @type {Schemas}
+   */
+  hedSchemas
+
+  /**
+   * Constructor.
+   *
+   * @param {BidsTsvFile} tsvFile The BIDS TSV file being parsed.
+   * @param {Schemas} hedSchemas The HED schema collection being parsed against.
+   */
+  constructor(tsvFile, hedSchemas) {
+    this.tsvFile = tsvFile
+    this.hedSchemas = hedSchemas
+  }
+
+  /**
+   * Combine the BIDS bidsFile HED data into a BIDS TSV file's HED data.
+   *
+   * @returns {Array} - Returns a two-element array [BidsTsvElement[], BidsHedIssue[]].
+   */
+  parse() {
+    const tsvHedRows = this._generateHedRows()
+    const tsvElements = this._parseHedRows(tsvHedRows)
+    const parsingIssues = this._parseElementStrings(tsvElements)
+    return [tsvElements, parsingIssues]
+  }
+
+  /**
+   * Parse element HED strings.
+   *
+   * @param {BidsTsvElement[]} elements - The objects representing tsv rows with their parsed HEd strings.
+   * @returns {BidsHedIssue[]} - The issues resulting in creating the parsed HED strings.
+   */
+  _parseElementStrings(elements) {
+    if (elements.length === 0) {
+      return []
+    }
+
+    // Add the parsed HED strings to the elements and quite if there are serious errors
+    const cummulativeIssues = []
+    for (const element of elements) {
+      const [parsedHedString, parsingIssues] = parseHedString(element.hedString, this.hedSchemas, false, false)
+      element.parsedHedString = parsedHedString
+      if (parsingIssues.length > 0) {
+        cummulativeIssues.push(
+          ...BidsHedIssue.fromHedIssues(parsingIssues, this.tsvFile.file, { tsvLine: element.tsvLine }),
+        )
+      }
+    }
+    return cummulativeIssues
+  }
+
+  /**
+   * Generate a list of rows with column-to-value mappings.
+   *
+   * @returns {Array.Map} A list of single-row column-to-value mappings.
+   * @private
+   */
+  _generateHedRows() {
+    const tsvHedColumns = Array.from(this.tsvFile.parsedTsv.entries()).filter(
+      ([header]) => this.tsvFile.mergedSidecar.hedData.has(header) || header === 'HED' || header === 'onset',
+    )
+
+    const tsvHedRows = []
+    for (const [header, data] of tsvHedColumns) {
+      data.forEach((value, index) => {
+        tsvHedRows[index] ??= new Map()
+        tsvHedRows[index].set(header, value)
+      })
+    }
+    return tsvHedRows
+  }
+
+  /**
+   * Parse the rows in the TSV file into HED strings.
+   *
+   * @param {Map[]} tsvHedRows - A list of single-row column-to-value mappings.
+   * @returns {BidsTsvRow[]} - A list of row-based parsed HED strings.
+   * @private
+   */
+  _parseHedRows(tsvHedRows) {
+    const hedRows = []
+    tsvHedRows.forEach((row, index) => {
+      const hedRow = this._parseHedRow(row, index + 2)
+      if (hedRow !== null) {
+        hedRows.push(hedRow)
+      }
+    })
+    return hedRows
+  }
+
+  /**
+   * Parse a row in a TSV file into a BIDS row.
+   *
+   * @param {Map} rowCells - The column-to-value mapping for a single row.
+   * @param {number} tsvLine - The index of this row in the TSV file.
+   * @returns {BidsTsvRow} - A parsed HED string.
+   * @private
+   */
+  _parseHedRow(rowCells, tsvLine) {
+    const hedStringParts = []
+    const columnMap = this._getColumnMapping(rowCells)
+    this.spliceValues(columnMap)
+
+    for (const [columnName, columnValue] of rowCells.entries()) {
+      // If a splice, it can't be used in an assembled HED string.
+      if (
+        this.tsvFile.mergedSidecar.columnSpliceReferences.has(columnName) ||
+        BidsHedTsvParser.nullSet.has(columnValue)
+      ) {
+        continue
+      }
+      if (columnMap.has(columnName) && !BidsHedTsvParser.nullSet.has(columnMap.get(columnName))) {
+        hedStringParts.push(columnMap.get(columnName))
+      }
+    }
+    const hedString = hedStringParts.join(',')
+    if (hedString === '' || hedString === 'n/a') {
+      return null
+    }
+    return new BidsTsvRow(hedString, this.tsvFile, tsvLine, rowCells)
+  }
+
+  /**
+   * Generate a mapping from tsv columns to strings (may have splices in the strings)
+   *
+   * @param {Map} rowCells - The column-to-value mapping for a single row.
+   * @returns {Map} - A mapping of column names to their corresponding parsed bidsFile strings.
+   * @private
+   */
+  _getColumnMapping(rowCells) {
+    const columnMap = new Map()
+
+    if (rowCells.has('HED')) {
+      columnMap.set('HED', rowCells.get('HED'))
+    }
+
+    if (!this.tsvFile.mergedSidecar.hasHedData()) {
+      return columnMap
+    }
+
+    // Check for the columns with HED data in the bidsFile
+    for (const [columnName, columnValues] of this.tsvFile.mergedSidecar.parsedHedData.entries()) {
+      if (!rowCells.has(columnName)) {
+        continue
+      }
+      const rowColumnValue = rowCells.get(columnName)
+      if (rowColumnValue === 'n/a' || rowColumnValue === '') {
+        columnMap.set(columnName, '')
+        continue
+      }
+
+      if (columnValues instanceof ParsedHedString) {
+        const columnString = columnValues.hedString.replace('#', rowColumnValue)
+        columnMap.set(columnName, columnString)
+      } else if (columnValues instanceof Map) {
+        columnMap.set(columnName, columnValues.get(rowColumnValue).hedString)
+      }
+    }
+
+    return columnMap
+  }
+
+  /**
+   * Update the map to splice-in the values for columns that have splices.
+   *
+   * @param {Map} columnMap - Map of column name to HED string for a row.
+   *
+   * Note: Updates the map in place.
+   */
+  spliceValues(columnMap) {
+    // Only iterate over the column names that have splices
+    for (const column of this.tsvFile.mergedSidecar.columnSpliceMapping.keys()) {
+      if (!columnMap.has(column)) {
+        continue
+      }
+      const unspliced = columnMap.get(column)
+      const result = this._replaceSplices(unspliced, columnMap)
+      columnMap.set(column, result)
+    }
+  }
+
+  /**
+   * Replace a HED string containing slices with a resolved version for the column value in a row.
+   *
+   * @param {string} unspliced - A HED string possibly with unresolved splices.
+   * @param {Map} columnMap - The map of column name to HED string for a row.
+   * @returns {string} - The fully resolved HED string with no splices.
+   * @private
+   */
+  _replaceSplices(unspliced, columnMap) {
+    const result = unspliced.replace(BidsHedTsvParser.braceRegEx, (match, content) => {
+      // Resolve the replacement value
+      const resolved = columnMap.has(content) ? columnMap.get(content) : ''
+      // Replace with resolved value or empty string if in nullSet
+      return BidsHedTsvParser.nullSet.has(resolved) ? '' : resolved
+    })
+    return this._spliceCleanup(result)
+  }
+
+  /**
+   * Remove empty tags or groups which occur because of an empty splice.
+   * @param {string} spliced - The result of splice removal -- which could have empty tags or groups.
+   * @returns {string} - The string with empty tags or groups removed.
+   * @private
+   */
+  _spliceCleanup(spliced) {
+    let result = spliced
+
+    // Remove extra internal empty parentheses due to empty splices
+    while (BidsHedTsvParser.parenthesesRegEx.test(result)) {
+      result = result.replace(BidsHedTsvParser.parenthesesRegEx, '')
+    }
+    // Remove leading commas
+    result = result.replace(BidsHedTsvParser.leadingCommaRegEx, '')
+
+    // Remove trailing commas
+    result = result.replace(BidsHedTsvParser.trailingCommaRegEx, '')
+
+    // Remove extra empty commas due to empty splices
+    return result.replace(BidsHedTsvParser.internalCommaRegEx, ',')
+  }
+}
+
+export default BidsHedTsvValidator
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/bids_validator_validator.js.html b/docs/html/bids_validator_validator.js.html new file mode 100644 index 00000000..2c02f740 --- /dev/null +++ b/docs/html/bids_validator_validator.js.html @@ -0,0 +1,213 @@ + + + + + JSDoc: Source: bids/validator/validator.js + + + + + + + + + +
+

Source: bids/validator/validator.js

+ +
+
+
/**
+ * Validator base class for HED data in BIDS TSV files.
+ */
+export class BidsValidator {
+  /**
+   * The BIDS file being validated.
+   * @type {BidsFile}
+   */
+  bidsFile
+  /**
+   * The HED schema collection being validated against.
+   * @type {Schemas}
+   */
+  hedSchemas
+  /**
+   * The issues found during validation.
+   * @type {BidsIssue[]}
+   */
+  issues
+
+  /**
+   * Bids validator base class.
+   *
+   * @param {BidsFile} bidsFile - The BIDS TSV file being validated.
+   * @param {Schemas} hedSchemas - The HED schemas used for validation.
+   */
+  constructor(bidsFile, hedSchemas) {
+    this.bidsFile = bidsFile
+    this.hedSchemas = hedSchemas // Will be set when the file is validated
+    this.issues = []
+  }
+
+  /**
+   * Validate a BIDS TSV file. This method returns the complete issue list for convenience.
+   *
+   * @returns {BidsIssue[]} - Any issues found during validation of this TSV file.
+   */
+  validate() {
+    return this.issues
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/fonts/OpenSans-Bold-webfont.eot b/docs/html/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 00000000..5d20d916 Binary files /dev/null and b/docs/html/fonts/OpenSans-Bold-webfont.eot differ diff --git a/docs/html/fonts/OpenSans-Bold-webfont.svg b/docs/html/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 00000000..3ed7be4b --- /dev/null +++ b/docs/html/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/html/fonts/OpenSans-Bold-webfont.woff b/docs/html/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 00000000..1205787b Binary files /dev/null and b/docs/html/fonts/OpenSans-Bold-webfont.woff differ diff --git a/docs/html/fonts/OpenSans-BoldItalic-webfont.eot b/docs/html/fonts/OpenSans-BoldItalic-webfont.eot new file mode 100644 index 00000000..1f639a15 Binary files /dev/null and b/docs/html/fonts/OpenSans-BoldItalic-webfont.eot differ diff --git a/docs/html/fonts/OpenSans-BoldItalic-webfont.svg b/docs/html/fonts/OpenSans-BoldItalic-webfont.svg new file mode 100644 index 00000000..6a2607b9 --- /dev/null +++ b/docs/html/fonts/OpenSans-BoldItalic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/html/fonts/OpenSans-BoldItalic-webfont.woff b/docs/html/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 00000000..ed760c06 Binary files /dev/null and b/docs/html/fonts/OpenSans-BoldItalic-webfont.woff differ diff --git a/docs/html/fonts/OpenSans-Italic-webfont.eot b/docs/html/fonts/OpenSans-Italic-webfont.eot new file mode 100644 index 00000000..0c8a0ae0 Binary files /dev/null and b/docs/html/fonts/OpenSans-Italic-webfont.eot differ diff --git a/docs/html/fonts/OpenSans-Italic-webfont.svg b/docs/html/fonts/OpenSans-Italic-webfont.svg new file mode 100644 index 00000000..e1075dcc --- /dev/null +++ b/docs/html/fonts/OpenSans-Italic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/html/fonts/OpenSans-Italic-webfont.woff b/docs/html/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 00000000..ff652e64 Binary files /dev/null and b/docs/html/fonts/OpenSans-Italic-webfont.woff differ diff --git a/docs/html/fonts/OpenSans-Light-webfont.eot b/docs/html/fonts/OpenSans-Light-webfont.eot new file mode 100644 index 00000000..14868406 Binary files /dev/null and b/docs/html/fonts/OpenSans-Light-webfont.eot differ diff --git a/docs/html/fonts/OpenSans-Light-webfont.svg b/docs/html/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 00000000..11a472ca --- /dev/null +++ b/docs/html/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/html/fonts/OpenSans-Light-webfont.woff b/docs/html/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 00000000..e7860748 Binary files /dev/null and b/docs/html/fonts/OpenSans-Light-webfont.woff differ diff --git a/docs/html/fonts/OpenSans-LightItalic-webfont.eot b/docs/html/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 00000000..8f445929 Binary files /dev/null and b/docs/html/fonts/OpenSans-LightItalic-webfont.eot differ diff --git a/docs/html/fonts/OpenSans-LightItalic-webfont.svg b/docs/html/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 00000000..431d7e35 --- /dev/null +++ b/docs/html/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,1835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/html/fonts/OpenSans-LightItalic-webfont.woff b/docs/html/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 00000000..43e8b9e6 Binary files /dev/null and b/docs/html/fonts/OpenSans-LightItalic-webfont.woff differ diff --git a/docs/html/fonts/OpenSans-Regular-webfont.eot b/docs/html/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 00000000..6bbc3cf5 Binary files /dev/null and b/docs/html/fonts/OpenSans-Regular-webfont.eot differ diff --git a/docs/html/fonts/OpenSans-Regular-webfont.svg b/docs/html/fonts/OpenSans-Regular-webfont.svg new file mode 100644 index 00000000..25a39523 --- /dev/null +++ b/docs/html/fonts/OpenSans-Regular-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/html/fonts/OpenSans-Regular-webfont.woff b/docs/html/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 00000000..e231183d Binary files /dev/null and b/docs/html/fonts/OpenSans-Regular-webfont.woff differ diff --git a/docs/html/global.html b/docs/html/global.html new file mode 100644 index 00000000..a6ca1745 --- /dev/null +++ b/docs/html/global.html @@ -0,0 +1,3798 @@ + + + + + JSDoc: Global + + + + + + + + + +
+

Global

+ +
+
+

+
+ +
+
+
+
+ +

Members

+ +

+ (constant) capitalizeString +

+ +
Get a copy of a string with the first letter capitalized.
+ +
+
Source:
+
+ +
+
+ +

+ destinationTags +

+ +
The destination schema's tag collection.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) find +

+ +
Execute an XPath query on an xml2js object.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) generateIssue +

+ +
Generate a new issue object.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) getCharacterCount +

+ +
Get number of instances of an character in a string.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) getElementCount +

+ +
Get number of instances of an element in an array.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) getGenerationForSchemaVersion +

+ +
Determine the HED generation for a base schema version number.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) getParentTag +

+ +
Get the HED tag prefix (up to the last slash).
+ +
+
Source:
+
+ +
+
+ +

+ (constant) getTagName +

+ +
Get the last part of a HED tag.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) getTagSlashIndices +

+ +
Get the indices of all slashes in a HED tag.
+ +
+
Source:
+
+ +
+
+ +

+ hasUnitClass +

+ +
Checks if this HED tag has the {@code unitClass} attribute.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) hedStringIsAGroup +

+ +
Determine whether a HED string is a group (surrounded by parentheses).
+ +
+
Source:
+
+ +
+
+ +

+ (constant) isClockFaceTime +

+ +
Determine if a string is a valid clock face time.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) isDateTime +

+ +
Determine if a string is a valid date-time.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) isNumber +

+ +
Determine if a string is a valid number.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) localSchemaList +

+ +
Bundled HED schema configuration.
+ +
+
Source:
+
+ +
+
+ +

+ normalized +

+ +
Return a normalized string representation
+ +
+
Source:
+
+ +
+
+ +

+ normalized +

+ +
Return the normalized version of this tag.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) removeGroupParentheses +

+ +
Return a copy of a group tag with the surrounding parentheses removed.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) replaceTagNameWithPound +

+ +
Replace the end of a HED tag with a pound sign.
+ +
+
Source:
+
+ +
+
+ +

+ schemaTag +

+ +
Get the schema tag object for this tag.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) setParent +

+ +
Handle top level of parent-setting recursion before passing to setNodeParent.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) sidecarValueHasHed +

+ +
Determine whether a bidsFile value has HED data.
+ +
+
Source:
+
+ +
+
+ +

+ sourceTags +

+ +
The source schema's tag collection.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) stringIsEmpty +

+ +
Check if a string is empty or only whitespace.
+ +
+
Source:
+
+ +
+
+ +

+ (constant) stringTemplate +

+ +
+ Parse a template literal string. Copied from + https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals. +
+ +
+
Source:
+
+ +
+
+ +

+ takesValue +

+ +
Checks if this HED tag has the {@code takesValue} attribute.
+ +
+
Source:
+
+ +
+
+ +

+ takesValueTag +

+ +
Get the schema tag object for this tag's value-taking form.
+ +
+
Source:
+
+ +
+
+ +

+ unitClasses +

+ +
Get the unit classes for this HED tag.
+ +
+
Source:
+
+ +
+
+ +

Methods

+ +

+ _convertTag(hedSchemas, hedString, tagSpec) +

+ +
Convert this tag to its various forms
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hedSchemas + Schemas + The collection of HED schemas.
hedString + string + The original HED string.
tagSpec + TagSpec + The token for this tag.
+ +
+
Source:
+
+ +
+
+ +
Throws:
+ +
+
+
If tag conversion or parsing fails.
+
+
+
+
+
Type
+
+ IssueError +
+
+
+
+
+ +

+ _createParsedGroups(tags, groupSpecs) → {Array.<ParsedHedGroup>} +

+ +
Create parsed HED groups from parsed tags and group specifications.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tags + Array.<ParsedHedTag> + The parsed HED tags.
groupSpecs + Array.<GroupSpec> + The group specifications.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The parsed HED groups.
+ +
+
Type
+
+ Array.<ParsedHedGroup> +
+
+ +

+ _createParsedTags(tagSpecs, groupSpecs) → {Array} +

+ +
Create parsed HED tags and groups from specifications.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tagSpecs + Array.<TagSpec> + The tag specifications.
groupSpecs + GroupSpec + The group specifications.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+ - [ParsedHedSubstring[], Issue[]] representing the parsed HED tags and any issues found. +
+ +
+
Type
+
+ Array +
+
+ +

+ _getSplitValue(remainder) +

+ +
Handle reserved three-level tags.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
remainder + string + The remainder of the tag string after schema tag.
+ +
+
Source:
+
+ +
+
+ +

+ _handleIssueError(issueError) +

+ +
Handle any issue encountered during tag parsing.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
issueError + Error + | + + IssueError + The error encountered.
+ +
+
Source:
+
+ +
+
+ +

+ (protected) _memoize(propertyName, valueComputer) → {T} +

+ +
Memoize a property.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
propertyName + string + The property name.
valueComputer + function + A function to compute the property's value.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The computed value.
+ +
+
Type
+
+ T +
+
+ +

+ _separateUnits(schemaTag, remainder) → {Array} +

+ +
Separate the remainder of the tag into three parts.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaTag + SchemaTag + The part of the tag that is in the schema.
remainder + string + The leftover part.
+ +
+
Source:
+
+ +
+
+ +
Throws:
+ +
+
+
- If parsing the remainder section fails.
+
+
+
+
+
Type
+
+ IssueError +
+
+
+
+
+ +
Returns:
+ +
+ - [SchemaUnit, string, string] representing the actual Unit, the unit string and the value string. +
+ +
+
Type
+
+ Array +
+
+ +

+ buildBidsSchemas(datasetDescription, schemaDefinition) → {Promise} +

+ +
Build a HED schema collection based on the defined BIDS schemas.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
datasetDescription + BidsJsonFile + The description of the BIDS dataset being validated.
schemaDefinition + SchemasSpec + The version spec override for the schema to be loaded.
+ +
+
Source:
+
+ +
+
+ +
Throws:
+ +
+
+
If the schema specification is invalid.
+
+
+
+
+
Type
+
+ IssueError +
+
+
+
+
+ +
Returns:
+ +
A Promise with the schema collection, or null if the specification is missing.
+ +
+
Type
+
+ Promise +
+
+ +

+ buildSchemaObject(xmlData) → {Schema} +

+ +
Build a single schema container object from an XML file.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xmlData + object + The schema's XML data
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The HED schema object.
+ +
+
Type
+
+ Schema +
+
+ +

+ buildSchemaObjects(xmlData) → {Schema} +

+ +
Build a single merged schema container object from one or more XML files.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xmlData + Array.<object> + The schemas' XML data.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The HED schema object.
+ +
+
Type
+
+ Schema +
+
+ +

+ buildSchemas(schemaSpecs) → {Promise.<Schemas>} +

+ +
Build a schema collection object from a schema specification.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaSpecs + SchemasSpec + The description of which schemas to use.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The schema container object and any issues found.
+ +
+
Type
+
+ Promise.<Schemas> +
+
+ +

+ buildSchemasSpec(datasetDescription, schemaDefinition) → {SchemasSpec|null} +

+ +
Build a HED schema specification based on the defined BIDS schemas.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
datasetDescription + BidsJsonFile + The description of the BIDS dataset being validated.
schemaDefinition + SchemasSpec + The version spec override for the schema to be loaded.
+ +
+
Source:
+
+ +
+
+ +
Throws:
+ +
+
+
If the schema specification is invalid.
+
+
+
+
+
Type
+
+ IssueError +
+
+
+
+
+ +
Returns:
+ +
+ The schema specification to be used to build the schemas, or null if the specification is missing. +
+ +
+
Type
+
+ SchemasSpec + | + + null +
+
+ +

+ categorizeTagsByName(tagList, tagNames) → {Map} +

+ +
Create a map of the ParsedHedTags by type.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tagList + Array.<ParsedHedTag> + The HED tags to be categorized.
tagNames + Set + The tag names to use as categories.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- A map (string --> ParsedHedTag) of tag name to a list of tags with that name.
+ +
+
Type
+
+ Map +
+
+ +

+ checkValue(value) → {boolean} +

+ +
Check if value is a valid value for this tag.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + string + The value to be checked.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The result of check -- false if not a valid value.
+ +
+
Type
+
+ boolean +
+
+ +

+ (generator) columnSpliceIterator() + → {ParsedHedColumnSplice} +

+ +
Iterator over the parsed HED column splices in this HED tag group.
+ +
+
Source:
+
+ +
+
+ +
Yields:
+ +
This tag group's HED column splices.
+ +
+
Type
+
+ ParsedHedColumnSplice +
+
+ +

+ convert() → {Array} +

+ +
+ Retrieve the SchemaTag object for a tag specification. +
+ +
+
Source:
+
+ +
+
+ +
Throws:
+ +
+
+
If tag conversion.
+
+
+
+
+
Type
+
+ IssueError +
+
+
+
+
+ +
Returns:
+ +
+ - [SchemaTag, string] representing schema's corresponding tag object and the remainder of the tag string. +
+ +
+
Type
+
+ Array +
+
+ +

+ convertParsedTSVData(oldParsedTsv) → {Array.<Map>} +

+ +
Convert parsed TSV file data from the old BIDS format to the new BIDS format.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
oldParsedTsv + Object + Parsed TSV data using the old format
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The parsed contents of the TSV file, using the new format.
+ +
+
Type
+
+ Array.<Map> +
+
+ +

+ equivalent(other) → {boolean} +

+ +
+ Determine if this HED tag is equivalent to another HED tag. Note: HED tags are deemed equivalent if they + have the same schema and normalized tag string. +
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
other + ParsedHedTag + A HED tag to compare with this one.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
Whether other True, if other is equivalent to this HED tag.
+ +
+
Type
+
+ boolean +
+
+ +

+ filterByClass(items, classType) + → {Array.<ParsedHedSubstring>} +

+ +
Extract the items of a specified subtype from a list of ParsedHedSubstring
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
items + Array.<ParsedHedSubstring> + Objects to be filtered by class type.
classType + Class + The class type to filter by.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- A list of objects of the specified subclass of ParsedHedSubstring
+ +
+
Type
+
+ Array.<ParsedHedSubstring> +
+
+ +

+ filterByTagName(tags, tagName) → {Array.<ParsedHedTag>} +

+ +
Extract the ParsedHedTag tags with a specified tag name
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tags + Array.<ParsedHedTag> + to be filtered by name
tagName + string + name of the tag to filter by
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+
Type
+
+ Array.<ParsedHedTag> +
+
+ +

+ filterTagMapByNames(tagMap, tagNames) → {Array.<ParsedHedTag>} +

+ +
Extract the ParsedHedTag tags with a specified tag name.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tagMap + Map.<string, Array.<ParsedHedTag>> + The Map of parsed HED tags for extraction (must be defined).
tagNames + Array.<string> + The names to use as keys for the filter.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- A list of temporal tags.
+ +
+
Type
+
+ Array.<ParsedHedTag> +
+
+ +

+ format(long) → {string} +

+ +
Nicely format this tag group.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
long + boolean + trueWhether the tags should be in long form.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+
Type
+
+ string +
+
+ +

+ format(long) → {string} +

+ +
Nicely format this tag.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
long + boolean + trueWhether the tags should be in long form.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- The nicely formatted version of this tag.
+ +
+
Type
+
+ string +
+
+ +

+ getAllTags(tagElementName) → {Map.<Object, string>} +

+ +
Retrieve all the tags in the schema.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
tagElementName + string + nodeThe name of the tag element.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The tag names and XML elements.
+ +
+
Type
+
+ Map.<Object, string> +
+
+ +

+ getDuplicates(itemList) → {Array.<string>} +

+ +
Return a list of duplicate strings.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
itemList + Array.<string> + A list of strings to look for duplicates in.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- A list of unique duplicate strings (multiple copies not repeated).
+ +
+
Type
+
+ Array.<string> +
+
+ +

+ getElementTagName(element) → {string} +

+ +
+ Extract the name of an XML element. NOTE: This method cannot be merged into + getElementTagValue because it is used as a first-class object. +
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
element + object + An XML element.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The name of the element.
+ +
+
Type
+
+ string +
+
+ +

+ getElementTagValue(element, tagName) → {string} +

+ +
Extract a value from an XML element.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
element + object + An XML element.
tagName + string + The tag value to extract.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The value of the tag in the element.
+ +
+
Type
+
+ string +
+
+ +

+ getTagListString(tagList) → {string} +

+ +
+ Convert a list of ParsedHedTag objects into a comma-separated string of their string representations. +
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tagList + Array.<ParsedHedTag> + + The HED tags whose string representations should be put in a comma-separated list. +
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
A comma separated list of original tag names for tags in tagList.
+ +
+
Type
+
+ string +
+
+ +

+ hasAttribute(attribute) → {boolean} +

+ +
Determine whether this tag has a given attribute.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
attribute + string + An attribute name.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
Whether this tag has the named attribute.
+ +
+
Type
+
+ boolean +
+
+ +

+ (async) loadBundledSchema(schemaDef) → {Promise.<object>} +

+ +
Load schema XML data from a bundled file.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaDef + SchemaSpec + The description of which schema to use.
+ +
+
Source:
+
+ +
+
+ +
Throws:
+ +
+
+
If the schema could not be loaded.
+
+
+
+
+
Type
+
+ IssueError +
+
+
+
+
+ +
Returns:
+ +
The schema XML data.
+ +
+
Type
+
+ Promise.<object> +
+
+ +

+ loadLocalSchema(path) → {Promise.<object>} +

+ +
Load schema XML data from a local file.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + string + The path to the schema XML data.
+ +
+
Source:
+
+ +
+
+ +
Throws:
+ +
+
+
If the schema could not be loaded.
+
+
+
+
+
Type
+
+ IssueError +
+
+
+
+
+ +
Returns:
+ +
The schema XML data.
+ +
+
Type
+
+ Promise.<object> +
+
+ +

+ (async) loadPromise(schemaDef) → {Promise.<Object>} +

+ +
Choose the schema Promise from a schema version or path description.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaDef + SchemaSpec + The description of which schema to use.
+ +
+
Source:
+
+ +
+
+ +
Throws:
+ +
+
+
If the schema could not be loaded.
+
+
+
+
+
Type
+
+ IssueError +
+
+
+
+
+ +
Returns:
+ +
The schema XML data.
+ +
+
Type
+
+ Promise.<Object> +
+
+ +

+ loadRemoteSchema(schemaDef) → {Promise.<object>} +

+ +
Load schema XML data from the HED GitHub repository.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaDef + SchemaSpec + The standard schema version to load.
+ +
+
Source:
+
+ +
+
+ +
Throws:
+ +
+
+
If the schema could not be loaded.
+
+
+
+
+
Type
+
+ IssueError +
+
+
+
+
+ +
Returns:
+ +
The schema XML data.
+ +
+
Type
+
+ Promise.<object> +
+
+ +

+ (async) loadSchemaFile(xmlDataPromise, issueCode, issueArgs) → {Promise.<object>} +

+ +
Actually load the schema XML file.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xmlDataPromise + Promise.<string> + The Promise containing the unparsed XML data.
issueCode + string + The issue code.
issueArgs + Object.<string, string> + The issue arguments passed from the calling function.
+ +
+
Source:
+
+ +
+
+ +
Throws:
+ +
+
+
If the schema could not be loaded.
+
+
+
+
+
Type
+
+ IssueError +
+
+
+
+
+ +
Returns:
+ +
The parsed schema XML data.
+ +
+
Type
+
+ Promise.<object> +
+
+ +

+ mergeSchemas() → {PartneredSchema} +

+ +
Merge the lazy partnered schemas.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The merged partnered schema.
+ +
+
Type
+
+ PartneredSchema +
+
+ +

+ parseHedString(hedString, hedSchemas, definitionsAllowed, placeholdersAllowed) → {Array} +

+ +
Parse a HED string.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hedString + string + | + + ParsedHedString + A (possibly already parsed) HED string.
hedSchemas + Schemas + The collection of HED schemas.
definitionsAllowed + boolean + True if definitions are allowed.
placeholdersAllowed + boolean + True if placeholders are allowed.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+ - [ParsedHedString, Issue[]] representing the parsed HED string and any issues found. +
+ +
+
Type
+
+ Array +
+
+ +

+ parseHedStrings(hedStrings, hedSchemas, definitionsAllowed, placeholdersAllowed) → {Array} +

+ +
Parse a list of HED strings.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hedStrings + Array.<string> + | + + Array.<ParsedHedString> + A list of HED strings.
hedSchemas + Schemas + The collection of HED schemas.
definitionsAllowed + boolean + True if definitions are allowed
placeholdersAllowed + boolean + True if placeholders are allowed
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+ - [ParsedHedString[], Issue[]] representing the parsed HED strings and any issues found. +
+ +
+
Type
+
+ Array +
+
+ +

+ parseSchemaXML(data) → {Promise.<object>} +

+ +
Parse the schema XML data.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + string + The XML data.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The schema XML data.
+ +
+
Type
+
+ Promise.<object> +
+
+ +

+ parseTSV(contents) → {Array.<Map>} +

+ +
Parse a TSV file.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
contents + string + The contents of a TSV file.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The parsed contents of the TSV file.
+ +
+
Type
+
+ Array.<Map> +
+
+ +

+ parseTags() +

+ +
Parse the schema's tags.
+ +
+
Source:
+
+ +
+
+ +

+ parseXPath(query) → {object} +

+ +
Parse an XPath query. This is a minimal parser only suitable for this package.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
query + string + An XPath query.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The parsed search parameters.
+ +
+
Type
+
+ object +
+
+ +

+ readFile(fileName) → {Promise} +

+ +
Read a local file.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fileName + string + The file path.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
- A promise with the file contents.
+ +
+
Type
+
+ Promise +
+
+ +

+ readHTTPSFile(url) → {Promise.<string>} +

+ +
Read a remote file using HTTPS.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
url + string + The remote URL.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
A promise with the file contents.
+ +
+
Type
+
+ Promise.<string> +
+
+ +

+ recursiveMap(fn, array) → {Array.<U>} +

+ +
Apply a function recursively to an array.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fn + function + The function to apply.
array + Array.<T> + The array to map.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The mapped array.
+ +
+
Type
+
+ Array.<U> +
+
+ + + +
Search for children of an element with a given name and attribute.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
element + object + An xml2js element.
elementName + string + The element name.
attributeName + string + The attribute name.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
An array of xml2js elements with the given name and attribute.
+ +
+
Type
+
+ Array.<object> +
+
+ +

+ setNodeParent(node, parent) +

+ +
Recursively set a field on each node of the tree pointing to the node's parent.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
node + object + The child node.
parent + object + The parent node.
+ +
+
Source:
+
+ +
+
+ +

+ splitHedString() → {Array} +

+ +
Split and parse a HED string into tags and groups.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
+ - [ParsedHedSubstring[], Issue[]] representing the parsed HED string data and any issues found. +
+ +
+
Type
+
+ Array +
+
+ +

+ stripBOM() +

+ +
+ Module for parsing TSV files. Adapted from + https://github.com/bids-standard/bids-validator/blob/6fc6d152b52266934575442e61f1477ba18f42ec/bids-validator/validators/tsv/tsvParser.js + and + https://github.com/bids-standard/bids-validator/blob/a5c63b445e3103bcc0843deac192033a9f0b4c5b/bids-validator/src/files/tsv.ts +
+ +
+
Source:
+
+ +
+
+ +

+ (generator) subParsedGroupIterator(tagName) → {ParsedHedGroup} +

+ +
Iterator over the ParsedHedGroup objects in this HED tag group.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
tagName + string + | + + null + null + The name of the tag whose groups are to be iterated over or null if all tags. +
+ +
+
Source:
+
+ +
+
+ +
Yields:
+ +
- This object and the ParsedHedGroup objects belonging to this tag group.
+ +
+
Type
+
+ ParsedHedGroup +
+
+ +

+ (generator) tagIterator() → {ParsedHedTag} +

+ +
Iterator over the parsed HED tags in this HED tag group.
+ +
+
Source:
+
+ +
+
+ +
Yields:
+ +
This tag group's HED tags.
+ +
+
Type
+
+ ParsedHedTag +
+
+ +

+ toString() → {string} +

+ +
Override of Object.prototype.toString.
+ +
+
Source:
+
+ +
+
+ +
Returns:
+ +
The original form of this HED tag.
+ +
+
Type
+
+ string +
+
+ +

+ (generator) topLevelGroupIterator() → {ParsedHedTag} +

+ +
Iterator over the top-level parsed HED groups in this HED tag group.
+ +
+
Source:
+
+ +
+
+ +
Yields:
+ +
This tag group's top-level HED groups.
+ +
+
Type
+
+ ParsedHedTag +
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/index.html b/docs/html/index.html new file mode 100644 index 00000000..de0bdc84 --- /dev/null +++ b/docs/html/index.html @@ -0,0 +1,168 @@ + + + + + JSDoc: Home + + + + + + + + + +
+

Home

+ +

+
+ + + +
+ + + + + + + diff --git a/docs/html/issues_issues.js.html b/docs/html/issues_issues.js.html new file mode 100644 index 00000000..0970b89e --- /dev/null +++ b/docs/html/issues_issues.js.html @@ -0,0 +1,332 @@ + + + + + JSDoc: Source: issues/issues.js + + + + + + + + + +
+

Source: issues/issues.js

+ +
+
+
import mapValues from 'lodash/mapValues'
+
+import issueData from './data'
+
+export class IssueError extends Error {
+  /**
+   * The associated HED issue.
+   * @type {Issue}
+   */
+  issue
+
+  constructor(issue, ...params) {
+    // Pass remaining arguments (including vendor specific ones) to parent constructor
+    super(...params)
+
+    // Maintains proper stack trace for where our error was thrown (only available on V8)
+    if (Error.captureStackTrace) {
+      Error.captureStackTrace(this, IssueError)
+    }
+
+    this.name = 'IssueError'
+    this.issue = issue
+    this.message = issue.message
+
+    Object.setPrototypeOf(this, IssueError.prototype)
+  }
+
+  /**
+   * Generate a new {@link Issue} object and immediately throw it as an {@link IssueError}.
+   *
+   * @param {string} internalCode The internal error code.
+   * @param {Object<string, (string|number[])>?} parameters The error string parameters.
+   * @throws {IssueError} Corresponding to the generated {@link Issue}.
+   */
+  static generateAndThrow(internalCode, parameters = {}) {
+    throw new IssueError(generateIssue(internalCode, parameters))
+  }
+}
+
+/**
+ * A HED validation error or warning.
+ */
+export class Issue {
+  /**
+   * The internal error code.
+   * @type {string}
+   */
+  internalCode
+
+  /**
+   * The HED 3 error code.
+   * @type {string}
+   */
+  hedCode
+  /**
+   * The issue level (error or warning).
+   * @type {string}
+   */
+  level
+  /**
+   * The detailed error message.
+   * @type {string}
+   */
+  message
+  /**
+   * The parameters to the error message template. Object with string and map parameters.
+   * @type {Object}
+   */
+  parameters
+
+  /**
+   * Constructor.
+   * @param {string} internalCode The internal error code.
+   * @param {string} hedCode The HED 3 error code.
+   * @param {string} level The issue level (error or warning).
+   * @param {Object} parameters The error string parameters.
+   */
+  constructor(internalCode, hedCode, level, parameters) {
+    this.internalCode = internalCode
+    this.hedCode = hedCode
+    this.level = level
+    this.parameters = parameters
+    this.generateMessage()
+  }
+
+  /**
+   * Whether this issue is an error.
+   *
+   * @returns {boolean}
+   */
+  isError() {
+    return this.level === 'error'
+  }
+
+  /**
+   * Override of {@link Object.prototype.toString}.
+   *
+   * @returns {string} This issue's message.
+   */
+  toString() {
+    return this.message
+  }
+
+  /**
+   * (Re-)generate the issue message.
+   */
+  generateMessage() {
+    // Convert all parameters except the substring bounds (an integer array) to their string forms.
+    this.parameters = mapValues(this.parameters, (value, key) => (key === 'bounds' ? value : String(value)))
+
+    const bounds = this.parameters.bounds ?? []
+    const messageTemplate = issueData[this.internalCode].message
+    let message = messageTemplate(...bounds, this.parameters)
+
+    // Special parameters
+    if (this.parameters.sidecarKey) {
+      message += ` Sidecar key: "${this.parameters.sidecarKey}".`
+    }
+    if (this.parameters.tsvLine) {
+      message += ` TSV line: ${this.parameters.tsvLine}.`
+    }
+    if (this.parameters.hedString) {
+      message += ` HED string: "${this.parameters.hedString}".`
+    }
+
+    // Append link to error code in HED spec.
+    const hedCodeAnchor = this.hedCode.toLowerCase().replace(/_/g, '-')
+    const hedSpecLink = `For more information on this HED ${this.level}, see https://hed-specification.readthedocs.io/en/latest/Appendix_B.html#${hedCodeAnchor}`
+
+    this.message = `${this.level.toUpperCase()}: [${this.hedCode}] ${message} (${hedSpecLink}.)`
+  }
+
+  /**
+   * Return a tuple with a boolean denoting overall validity and all issues.
+   *
+   * @param {Issue[]} issues A list of issues.
+   * @returns {Array} Returns [boolean, Issue[]] indicate if validation succeeded (i.e. any errors were found)and all issues (both errors and warnings).
+   */
+  static issueListWithValidStatus(issues) {
+    return [!issues.some((issue) => issue.isError()), issues]
+  }
+}
+
+/**
+ * Generate a new issue object.
+ *
+ * @param {string} internalCode The internal error code.
+ * @param {Object} parameters The error string parameters.
+ * @returns {Issue} An object representing the issue.
+ */
+export const generateIssue = function (internalCode, parameters) {
+  const issueCodeData = issueData[internalCode] ?? issueData.genericError
+  const { hedCode, level } = issueCodeData
+  if (issueCodeData === issueData.genericError) {
+    parameters.internalCode = internalCode
+    parameters.parameters = 'Issue parameters: ' + JSON.stringify(parameters)
+  }
+
+  return new Issue(internalCode, hedCode, level, parameters)
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/module.exports_module.exports.html b/docs/html/module.exports_module.exports.html new file mode 100644 index 00000000..7b1899e9 --- /dev/null +++ b/docs/html/module.exports_module.exports.html @@ -0,0 +1,294 @@ + + + + + JSDoc: Class: exports + + + + + + + + + +
+

Class: exports

+ +
+
+

+ exports(hedString, hedSchemas) +

+
+ +
+
+

+ new exports(hedString, hedSchemas) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hedString + string + The HED string to be split and parsed.
hedSchemas + Schemas + The collection of HED schemas.
+ +
+
Source:
+
+ +
+
+
+
+
+ +
+
+

+ exports(sourceSchemas) +

+
+ +
+
+

+ new exports(sourceSchemas) +

+ +
Constructor.
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sourceSchemas + Array.<Schema> + The sources of data to be merged.
+ +
+
Source:
+
+ +
+
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/module.html#.exports b/docs/html/module.html#.exports new file mode 100644 index 00000000..a3a994cd --- /dev/null +++ b/docs/html/module.html#.exports @@ -0,0 +1,10946 @@ + + + + + JSDoc: Class: exports + + + + + + + + + + +
+ +

Class: exports

+ + + + + + +
+ +
+ +

exports(parsedHedTags, hedString, originalBounds)

+ +
A parsed HED tag group.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(parsedHedTags, hedString, originalBounds)

+ + + + + + +
+ Constructor. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
parsedHedTags + + +Array.<ParsedHedSubstring> + + + + The parsed HED tags, groups or column splices in the HED tag group.
hedString + + +string + + + + The original HED string.
originalBounds + + +Array.<number> + + + + The bounds of the HED tag in the original HED string.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

allTags :Array.<ParsedHedTag>

+ + + + +
+ All the parsed HED tags in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

attributes :Map.<string, SchemaAttribute>

+ + + + + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

canonicalTag :string

+ + + + +
+ The canonical form of the HED tag. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

currentSource :Schema

+ + + + +
+ The current source of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defCount :Number

+ + + + +
+ The total number of top-level Def tags and top-level Def-expand groups. +
+ + + +
Type:
+
    +
  • + +Number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defExpandChildren :Array.<ParsedHedGroup>

+ + + + +
+ The top-level child subgroups containing Def-expand tags. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedGroup> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defExpandTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level Def-expand tags +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level Def tags +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

destination :PartneredSchema

+ + + + +
+ The destination of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

formattedTag :string

+ + + + +
+ The formatted canonical version of the HED tag. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedSchemas :Schemas

+ + + + +
+ The collection of HED schemas. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedSchemas :Schemas

+ + + + +
+ A HED schema collection. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedString :string

+ + + + +
+ The HED string being split. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

isDefinitionGroup :boolean

+ + + + +
+ True if this group has a Definition tag at the top level. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

properties :Map.<string, SchemaProperty>

+ + + + + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

remainder :string

+ + + + +
+ The remainder (e.g. value, extension) of the tag string. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

requiresDefTag :Array.<ParsedHedTag>|null

+ + + + +
+ The unique top-level tag requiring a Def or Def-expand group, if any. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> +| + +null + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

reservedTags :Map.<string, Array.<ParsedHedTag>>

+ + + + +
+ Reserved HED group tags. This only covers top group tags in the group. +
+ + + +
Type:
+
    +
  • + +Map.<string, Array.<ParsedHedTag>> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

rootElement :Object

+ + + + +
+ The root XML element. +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

schema :Schema

+ + + + +
+ The HED schema this tag belongs to. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

schemaTag :SchemaTag

+ + + + +
+ The converted tag in the schema. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

sourceSchemas :Array.<Schema>

+ + + + +
+ The sources of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagLevels :Array.<string>

+ + + + +
+ The tag string split by slashes. +
+ + + +
Type:
+
    +
  • + +Array.<string> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagMapping :SchemaTagManager

+ + + + +
+ The entry manager for the tags in the active schema. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagSlashes :Array.<number>

+ + + + +
+ The indices of the tag string's slashes. +
+ + + +
Type:
+
    +
  • + +Array.<number> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagSpec :TagSpec

+ + + + +
+ A parsed tag token. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagString :string

+ + + + +
+ The tag string to convert. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tags :Array.<ParsedHedSubstring>

+ + + + +
+ The parsed HED tags, groups, or splices in the HED tag group at the top level. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tags :SchemaTagManager

+ + + + +
+ The schema's tags. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topGroups :Array.<ParsedHedGroup>

+ + + + +
+ The top-level parsed HED groups in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedGroup> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topSplices :Array.<ParsedHedColumnSplice>

+ + + + +
+ The top-level column splices in this string +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level parsed HED tags in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

unitClasses :SchemaEntryManager.<SchemaUnitClass>

+ + + + +
+ The schema's unit classes. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

unitModifiers :SchemaEntryManager.<SchemaUnitModifier>

+ + + + +
+ The schema's unit modifiers. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

valueClasses :SchemaEntryManager.<SchemaValueClass>

+ + + + +
+ The schema's value classes. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports(tagSpec, hedSchemas, hedString)

+ +
A parsed HED tag.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(tagSpec, hedSchemas, hedString)

+ + + + + + +
+ Constructor. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tagSpec + + +TagSpec + + + + The token for this tag.
hedSchemas + + +Schemas + + + + The collection of HED schemas.
hedString + + +string + + + + The original HED string.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+ If tag conversion or parsing fails. +
+
+
+
+
+
+ Type +
+
+ +IssueError + + +
+
+
+
+
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

allTags :Array.<ParsedHedTag>

+ + + + +
+ All the parsed HED tags in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

attributes :Map.<string, SchemaAttribute>

+ + + + + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

canonicalTag :string

+ + + + +
+ The canonical form of the HED tag. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

currentSource :Schema

+ + + + +
+ The current source of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defCount :Number

+ + + + +
+ The total number of top-level Def tags and top-level Def-expand groups. +
+ + + +
Type:
+
    +
  • + +Number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defExpandChildren :Array.<ParsedHedGroup>

+ + + + +
+ The top-level child subgroups containing Def-expand tags. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedGroup> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defExpandTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level Def-expand tags +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level Def tags +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

destination :PartneredSchema

+ + + + +
+ The destination of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

formattedTag :string

+ + + + +
+ The formatted canonical version of the HED tag. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedSchemas :Schemas

+ + + + +
+ The collection of HED schemas. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedSchemas :Schemas

+ + + + +
+ A HED schema collection. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedString :string

+ + + + +
+ The HED string being split. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

isDefinitionGroup :boolean

+ + + + +
+ True if this group has a Definition tag at the top level. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

properties :Map.<string, SchemaProperty>

+ + + + + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

remainder :string

+ + + + +
+ The remainder (e.g. value, extension) of the tag string. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

requiresDefTag :Array.<ParsedHedTag>|null

+ + + + +
+ The unique top-level tag requiring a Def or Def-expand group, if any. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> +| + +null + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

reservedTags :Map.<string, Array.<ParsedHedTag>>

+ + + + +
+ Reserved HED group tags. This only covers top group tags in the group. +
+ + + +
Type:
+
    +
  • + +Map.<string, Array.<ParsedHedTag>> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

rootElement :Object

+ + + + +
+ The root XML element. +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

schema :Schema

+ + + + +
+ The HED schema this tag belongs to. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

schemaTag :SchemaTag

+ + + + +
+ The converted tag in the schema. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

sourceSchemas :Array.<Schema>

+ + + + +
+ The sources of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagLevels :Array.<string>

+ + + + +
+ The tag string split by slashes. +
+ + + +
Type:
+
    +
  • + +Array.<string> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagMapping :SchemaTagManager

+ + + + +
+ The entry manager for the tags in the active schema. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagSlashes :Array.<number>

+ + + + +
+ The indices of the tag string's slashes. +
+ + + +
Type:
+
    +
  • + +Array.<number> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagSpec :TagSpec

+ + + + +
+ A parsed tag token. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagString :string

+ + + + +
+ The tag string to convert. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tags :Array.<ParsedHedSubstring>

+ + + + +
+ The parsed HED tags, groups, or splices in the HED tag group at the top level. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tags :SchemaTagManager

+ + + + +
+ The schema's tags. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topGroups :Array.<ParsedHedGroup>

+ + + + +
+ The top-level parsed HED groups in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedGroup> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topSplices :Array.<ParsedHedColumnSplice>

+ + + + +
+ The top-level column splices in this string +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level parsed HED tags in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

unitClasses :SchemaEntryManager.<SchemaUnitClass>

+ + + + +
+ The schema's unit classes. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

unitModifiers :SchemaEntryManager.<SchemaUnitModifier>

+ + + + +
+ The schema's unit modifiers. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

valueClasses :SchemaEntryManager.<SchemaValueClass>

+ + + + +
+ The schema's value classes. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports(tagSpec, hedSchemas)

+ +
Converter from a tag specification to a schema-based tag object.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(tagSpec, hedSchemas)

+ + + + + + +
+ Constructor. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tagSpec + + +TagSpec + + + + The tag specification to convert.
hedSchemas + + +Schemas + + + + The HED schema collection.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

allTags :Array.<ParsedHedTag>

+ + + + +
+ All the parsed HED tags in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

attributes :Map.<string, SchemaAttribute>

+ + + + + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

canonicalTag :string

+ + + + +
+ The canonical form of the HED tag. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

currentSource :Schema

+ + + + +
+ The current source of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defCount :Number

+ + + + +
+ The total number of top-level Def tags and top-level Def-expand groups. +
+ + + +
Type:
+
    +
  • + +Number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defExpandChildren :Array.<ParsedHedGroup>

+ + + + +
+ The top-level child subgroups containing Def-expand tags. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedGroup> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defExpandTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level Def-expand tags +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level Def tags +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

destination :PartneredSchema

+ + + + +
+ The destination of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

formattedTag :string

+ + + + +
+ The formatted canonical version of the HED tag. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedSchemas :Schemas

+ + + + +
+ The collection of HED schemas. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedSchemas :Schemas

+ + + + +
+ A HED schema collection. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedString :string

+ + + + +
+ The HED string being split. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

isDefinitionGroup :boolean

+ + + + +
+ True if this group has a Definition tag at the top level. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

properties :Map.<string, SchemaProperty>

+ + + + + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

remainder :string

+ + + + +
+ The remainder (e.g. value, extension) of the tag string. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

requiresDefTag :Array.<ParsedHedTag>|null

+ + + + +
+ The unique top-level tag requiring a Def or Def-expand group, if any. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> +| + +null + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

reservedTags :Map.<string, Array.<ParsedHedTag>>

+ + + + +
+ Reserved HED group tags. This only covers top group tags in the group. +
+ + + +
Type:
+
    +
  • + +Map.<string, Array.<ParsedHedTag>> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

rootElement :Object

+ + + + +
+ The root XML element. +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

schema :Schema

+ + + + +
+ The HED schema this tag belongs to. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

schemaTag :SchemaTag

+ + + + +
+ The converted tag in the schema. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

sourceSchemas :Array.<Schema>

+ + + + +
+ The sources of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagLevels :Array.<string>

+ + + + +
+ The tag string split by slashes. +
+ + + +
Type:
+
    +
  • + +Array.<string> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagMapping :SchemaTagManager

+ + + + +
+ The entry manager for the tags in the active schema. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagSlashes :Array.<number>

+ + + + +
+ The indices of the tag string's slashes. +
+ + + +
Type:
+
    +
  • + +Array.<number> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagSpec :TagSpec

+ + + + +
+ A parsed tag token. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagString :string

+ + + + +
+ The tag string to convert. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tags :Array.<ParsedHedSubstring>

+ + + + +
+ The parsed HED tags, groups, or splices in the HED tag group at the top level. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tags :SchemaTagManager

+ + + + +
+ The schema's tags. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topGroups :Array.<ParsedHedGroup>

+ + + + +
+ The top-level parsed HED groups in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedGroup> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topSplices :Array.<ParsedHedColumnSplice>

+ + + + +
+ The top-level column splices in this string +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level parsed HED tags in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

unitClasses :SchemaEntryManager.<SchemaUnitClass>

+ + + + +
+ The schema's unit classes. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

unitModifiers :SchemaEntryManager.<SchemaUnitModifier>

+ + + + +
+ The schema's unit modifiers. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

valueClasses :SchemaEntryManager.<SchemaValueClass>

+ + + + +
+ The schema's value classes. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports()

+ +
Superclass for property memoization until we can get away with private fields.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports()

+ + + + + + +
+ Constructor. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

allTags :Array.<ParsedHedTag>

+ + + + +
+ All the parsed HED tags in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

attributes :Map.<string, SchemaAttribute>

+ + + + + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

canonicalTag :string

+ + + + +
+ The canonical form of the HED tag. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

currentSource :Schema

+ + + + +
+ The current source of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defCount :Number

+ + + + +
+ The total number of top-level Def tags and top-level Def-expand groups. +
+ + + +
Type:
+
    +
  • + +Number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defExpandChildren :Array.<ParsedHedGroup>

+ + + + +
+ The top-level child subgroups containing Def-expand tags. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedGroup> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defExpandTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level Def-expand tags +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

defTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level Def tags +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

destination :PartneredSchema

+ + + + +
+ The destination of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

formattedTag :string

+ + + + +
+ The formatted canonical version of the HED tag. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedSchemas :Schemas

+ + + + +
+ The collection of HED schemas. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedSchemas :Schemas

+ + + + +
+ A HED schema collection. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hedString :string

+ + + + +
+ The HED string being split. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

isDefinitionGroup :boolean

+ + + + +
+ True if this group has a Definition tag at the top level. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

properties :Map.<string, SchemaProperty>

+ + + + + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

remainder :string

+ + + + +
+ The remainder (e.g. value, extension) of the tag string. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

requiresDefTag :Array.<ParsedHedTag>|null

+ + + + +
+ The unique top-level tag requiring a Def or Def-expand group, if any. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> +| + +null + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

reservedTags :Map.<string, Array.<ParsedHedTag>>

+ + + + +
+ Reserved HED group tags. This only covers top group tags in the group. +
+ + + +
Type:
+
    +
  • + +Map.<string, Array.<ParsedHedTag>> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

rootElement :Object

+ + + + +
+ The root XML element. +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

schema :Schema

+ + + + +
+ The HED schema this tag belongs to. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

schemaTag :SchemaTag

+ + + + +
+ The converted tag in the schema. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

sourceSchemas :Array.<Schema>

+ + + + +
+ The sources of data to be merged. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagLevels :Array.<string>

+ + + + +
+ The tag string split by slashes. +
+ + + +
Type:
+
    +
  • + +Array.<string> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagMapping :SchemaTagManager

+ + + + +
+ The entry manager for the tags in the active schema. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagSlashes :Array.<number>

+ + + + +
+ The indices of the tag string's slashes. +
+ + + +
Type:
+
    +
  • + +Array.<number> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagSpec :TagSpec

+ + + + +
+ A parsed tag token. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tagString :string

+ + + + +
+ The tag string to convert. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tags :Array.<ParsedHedSubstring>

+ + + + +
+ The parsed HED tags, groups, or splices in the HED tag group at the top level. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

tags :SchemaTagManager

+ + + + +
+ The schema's tags. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topGroups :Array.<ParsedHedGroup>

+ + + + +
+ The top-level parsed HED groups in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedGroup> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topSplices :Array.<ParsedHedColumnSplice>

+ + + + +
+ The top-level column splices in this string +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

topTags :Array.<ParsedHedTag>

+ + + + +
+ The top-level parsed HED tags in this string. +
+ + + +
Type:
+
    +
  • + +Array.<ParsedHedTag> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

unitClasses :SchemaEntryManager.<SchemaUnitClass>

+ + + + +
+ The schema's unit classes. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

unitModifiers :SchemaEntryManager.<SchemaUnitModifier>

+ + + + +
+ The schema's unit modifiers. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

valueClasses :SchemaEntryManager.<SchemaValueClass>

+ + + + +
+ The schema's value classes. +
+ + + +
Type:
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/docs/html/parser_definitionChecker.js.html b/docs/html/parser_definitionChecker.js.html new file mode 100644 index 00000000..ab12e315 --- /dev/null +++ b/docs/html/parser_definitionChecker.js.html @@ -0,0 +1,362 @@ + + + + + JSDoc: Source: parser/definitionChecker.js + + + + + + + + + +
+

Source: parser/definitionChecker.js

+ +
+
+
import { generateIssue } from '../issues/issues'
+import { getTagListString } from './parseUtils'
+import Set from 'lodash/_Set'
+
+const DEFINITION_TAGS = new Set(['Definition', 'Def', 'Def-expand'])
+const DEF_GROUP_TAGS = new Set(['Definition', 'Def-expand'])
+
+export class DefinitionChecker {
+  /**
+   * Check Def-expand or definition syntax for compatible tags and number of groups
+   * @param {ParsedHedString} hedString - A group to check for Def-expand syntax.
+   */
+
+  constructor(hedString) {
+    this.hedString = hedString
+    this.definitionTags = this.hedString.tags.filter((tag) => tag.schemaTag.name === 'Definition')
+    this.defs = this.hedString.tags.filter((tag) => DEF_GROUP_TAGS.has(tag.schemaTag.name))
+  }
+
+  /**
+   * Do syntactical checks on Definition and Def-expand (without relying on presence of the definitions).
+   * @param {boolean} allowDefinitions - If False, definitions aren't allowed here at all.
+   * @returns {Issue[]} - list of issues when
+   */
+  check(allowDefinitions) {
+    // Definition checks are not relevant
+    if (this.defs.length === 0) {
+      return []
+    }
+
+    // Check that the definitions appear where they are allowed and without anything else.
+    const definitionIssues = this._checkDefinitionContext(allowDefinitions)
+    if (definitionIssues.length > 0) {
+      return definitionIssues
+    }
+
+    // Check that the structure of the Definition and Def-expand groups are correct.
+    return this._checkDefinitionStructure()
+  }
+
+  _checkDefinitionContext(allowDefinitions) {
+    // Definitions in a place where no definitions are allowed
+    if (!allowDefinitions && this.definitionTags.length > 0) {
+      return [
+        generateIssue('illegalDefinitionContext', {
+          definition: getTagListString(this.definitionTags),
+          string: this.hedString.hedString,
+        }),
+      ]
+    }
+    // If this HED string has definitions, it cannot have column splices
+    if (this.definitionTags.length > 0 && this.hedString.columnSplices.length > 0)
+      return [
+        generateIssue('curlyBracesInDefinition', {
+          definition: getTagListString(this.definitionTags),
+          column: this.hedString.columnSplices[0].originalTag,
+        }),
+      ]
+    // If any Def-expand or Definition tags are at the top level of the HED string
+    const badDefTags = this.hedString.topLevelTags.filter((tag) => DEF_GROUP_TAGS.has(tag.schemaTag.name))
+    if (badDefTags.length > 0) {
+      return [
+        generateIssue('missingTagGroup', {
+          tag: badDefTags[0],
+          string: this.hedString.hedString,
+        }),
+      ]
+    }
+    // Extra tags in a HED string with definitions.
+    if (this.hedString.topLevelTags.length > 0 && this.definitionTags.length > 0) {
+      return [
+        generateIssue('illegalInExclusiveContext', {
+          tag: this.definitionTags[0],
+          string: this.hedString.hedString,
+        }),
+      ]
+    }
+    // Non-definition groups in a HED string with definitions
+    let numberDefinitionGroups = 0
+    for (const group of this.hedString.tagGroups) {
+      if (group.isDefinitionGroup) {
+        numberDefinitionGroups += 1
+      }
+    }
+    if (numberDefinitionGroups > 0 && numberDefinitionGroups !== this.hedString.tagGroups.length) {
+      return [
+        generateIssue('illegalInExclusiveContext', {
+          tag: this.definitionTags[0],
+          string: this.hedString.hedString,
+        }),
+      ]
+    }
+    // Context okay.
+    return []
+  }
+
+  _checkDefinitionStructure() {
+    for (const topGroup of this.hedString.tagGroups) {
+      // This group has no definition group tags so go on.
+      if (!topGroup.allTags.some((tag) => !DEF_GROUP_TAGS.has(tag.schemaTag.name))) {
+        continue
+      }
+      let isTopGroup = true
+      for (const group of topGroup.subParsedGroupIterator()) {
+        const issues = this._checkGroupSyntax(group, isTopGroup)
+        if (issues.length > 0) {
+          return issues
+        }
+        isTopGroup = false
+      }
+    }
+    return []
+  }
+
+  /**
+   * Check the group syntax for definition and def-expand requirements
+   * @param {ParsedHedGroup} group - The group to be checked.
+   * @param {boolean} isTopGroup - True if this is a top group.
+   * @returns {Issue[]} - Returns an issue list of there is an error in the definition structure.
+   * @private
+   */
+  _checkGroupSyntax(group, isTopGroup) {
+    // If there are no definition or def-expand tags, no checks are needed.
+    if (group.defExpandTags.length + group.definitionTags.length === 0) {
+      return []
+    }
+
+    // Determine the base tag for error messages.
+    const errorTag = group.definitionTags.length > 0 ? group.definitionTags[0] : group.defExpandTags[0]
+
+    // Check if the Definition tag is in a top group.
+    if (errorTag.schemaTag.name === 'Definition' && !isTopGroup) {
+      return [generateIssue('invalidTopLevelTagGroupTag', { tag: errorTag, string: this.hedString.hedString })]
+    }
+
+    // Validate group structure: ensure one top tag and at most one top group.
+    if (group.topTags.length > 1 || group.topGroups.length > 1) {
+      return [generateIssue('invalidDefinitionGroupStructure', { tag: errorTag, tagGroup: group })]
+    }
+
+    // Definition or Def-expand groups can not have any Def, Definition, or Def-expand tags in subgroups.
+    const forbiddenTags = group.allTags.filter((tag) => tag !== errorTag && DEFINITION_TAGS.has(tag.schemaTag.name))
+    if (forbiddenTags.length > 0) {
+      return [generateIssue('invalidDefinitionForbidden', { tag: errorTag, tagGroup: group })]
+    }
+
+    // Def-expand group cannot have any column splices. (Definition tags have already been checked.)
+    if (group.defExpandTags.length > 0) {
+      const columnSplices = [...group.columnSpliceIterator()]
+      if (columnSplices.length > 0) {
+        return [
+          generateIssue('curlyBracesInDefinition', {
+            definition: getTagListString(group.defExpandTags),
+            column: columnSplices[0].originalTag,
+          }),
+        ]
+      }
+    }
+    return []
+  }
+
+  // _checkDefinitionSyntax(parsedString) {
+  //
+  //   // This checks whether there are any definitions in the string if the definition is allowed.
+  //   const definitionContextIssues = this._checkDefinitionContext(parsedString)
+  //   if (definitionContextIssues.length > 0) {
+  //     return definitionContextIssues
+  //   }
+  //
+  //   // If
+  //   const definitionStructureIssues = this._checkDefinitionStructure(parsedString)
+  //   return definitionStructureIssues
+  // }
+  //
+  //
+  //
+
+  // return issues
+  // const definitionTags = parsedString.tags.filter((tag) => tag.schemaTag.name === 'Definition')
+  // if (definitionTags.length > 0) {
+  //   return [
+  //     generateIssue('illegalDefinitionContext', {
+  //       definition: getTagListString(definitionTags),
+  //       string: parsedString.hedString,
+  //     }),
+  //   ]
+  // }
+  // return []
+  // }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_definitionManager.js.html b/docs/html/parser_definitionManager.js.html new file mode 100644 index 00000000..15ef5ee2 --- /dev/null +++ b/docs/html/parser_definitionManager.js.html @@ -0,0 +1,488 @@ + + + + + JSDoc: Source: parser/definitionManager.js + + + + + + + + + +
+

Source: parser/definitionManager.js

+ +
+
+
import { generateIssue, IssueError } from '../issues/issues'
+import { parseHedString } from './parser'
+import { filterByTagName } from './parseUtils'
+
+export class Definition {
+  /**
+   * The name of the definition.
+   * @type {string}
+   */
+  name
+
+  /**
+   * The name of the definition.
+   * @type {ParsedHedTag}
+   */
+  defTag
+
+  /**
+   * The parsed HED group representing the definition
+   * @type {ParsedHedGroup}
+   */
+  defGroup
+
+  /**
+   * The definition contents group
+   * @type {ParsedHedGroup}
+   */
+  defContents
+
+  placeholder
+
+  /**
+   * A single definition
+   *
+   * @param {ParsedHedGroup} definitionGroup - the parsedHedGroup representing the definition.
+   */
+  constructor(definitionGroup) {
+    this.defGroup = definitionGroup
+    this._initializeDefinition(definitionGroup)
+  }
+
+  _initializeDefinition(definitionGroup) {
+    if (definitionGroup.topTags?.length !== 1 || definitionGroup.topGroups?.length > 1) {
+      IssueError.generateAndThrow('invalidDefinition', { definition: definitionGroup.originalTag })
+    }
+    this.defTag = definitionGroup.topTags[0]
+    this.name = this.defTag._value
+    this.placeholder = this.defTag._splitValue
+    this.defContents = this.defGroup.topGroups.length > 0 ? this.defGroup.topGroups[0] : null
+  }
+
+  /**
+   * Return the evaluated definition contents and any issues.
+   * @param {ParsedHedTag} tag - The parsed HEd tag whose details should be checked.
+   * @param {Schemas} hedSchema - The HED schemas used to validate against.
+   * @param {boolean} placeholderAllowed - If true then placeholder is allowed in the def tag.
+   * @returns {Array} - Returns [string, Issue[]] containing the evaluated normalized definition string and any issues in the evaluation,
+   */
+  evaluateDefinition(tag, hedSchema, placeholderAllowed) {
+    // Check that the level of the value of tag agrees with the definition
+    if (!!this.defTag._splitValue !== !!tag._splitValue) {
+      const errorType = tag.schemaTag.name === 'Def' ? 'missingDefinitionForDef' : 'missingDefinitionForDefExpand'
+      return [null, [generateIssue(errorType, { definition: tag._value })]]
+    }
+    // Check that the evaluated definition contents okay (if two-level value)
+    if (!this.defContents) {
+      return ['', []]
+    }
+    if (!this.defTag._splitValue || (placeholderAllowed && tag._splitValue === '#')) {
+      return [this.defContents.normalized, []]
+    }
+    const evalString = this.defContents.originalTag.replace('#', tag._splitValue)
+    const [normalizedValue, issues] = parseHedString(evalString, hedSchema, false, false)
+    if (issues.length > 0) {
+      return [null, issues]
+    }
+    return [normalizedValue.normalized, []]
+  }
+
+  /**
+   * Return true if this definition is the same as the other.
+   * @param {Definition} other - Another definition to compare with this one.
+   * @returns {boolean} - True if the definitions are equivalent
+   */
+  equivalent(other) {
+    if (this.name !== other.name || this.defTag._splitValue !== other.defTag._splitValue) {
+      return false
+    } else if (this.defContents?.normalized !== other.defContents?.normalized) {
+      return false
+    }
+    return true
+  }
+
+  /**
+   * Verify that the placeholder count is correct in the definition.
+   * @returns {boolean} - True if the placeholder count is as expected.
+   * @private
+   */
+  _checkDefinitionPlaceholderCount() {
+    const placeholderCount = this.defContents ? this.defContents.originalTag.split('#').length - 1 : 0
+    return !((placeholderCount !== 1 && this.placeholder) || (placeholderCount !== 0 && !this.placeholder))
+  }
+
+  /**
+   * Create a list of Definition objects from a list of strings.
+   *
+   * @param {string} hedString - A list of string definitions.
+   * @param {Schemas} hedSchemas - The HED schemas to use in creation.
+   * @returns {Array} - Returns [Definition, Issue[]] with the definition and any issues.
+   */
+  static createDefinition(hedString, hedSchemas) {
+    const [parsedString, issues] = parseHedString(hedString, hedSchemas, true, true)
+    if (issues.length > 0) {
+      return [null, issues]
+    }
+    if (parsedString.topLevelTags.length !== 0 || parsedString.tagGroups.length > 1) {
+      return [null, [generateIssue('invalidDefinition', { definition: hedString })]]
+    }
+    return Definition.createDefinitionFromGroup(parsedString.tagGroups[0])
+  }
+
+  /**
+   * Create a definition from a ParsedHedGroup.
+   * @param {ParsedHedGroup} group - The group to create a definition from.
+   * @returns {Array} - Returns [Definition, Issue[]] with the definition and any issues. (The definition will be null if issues.)
+   */
+  static createDefinitionFromGroup(group) {
+    const def = new Definition(group)
+    if (def._checkDefinitionPlaceholderCount()) {
+      return [def, []]
+    }
+    return [null, [generateIssue('invalidPlaceholderInDefinition', { definition: def.defGroup.originalTag })]]
+  }
+}
+
+export class DefinitionManager {
+  /**
+   * Definitions for this manager (string --> Definition).
+   * @type {Map}
+   */
+  definitions
+
+  constructor() {
+    this.definitions = new Map()
+  }
+
+  /**
+   * Add the non-null definitions to this manager.
+   * @param {Definition[]} defs - The list of definitions to add to this manager.
+   * @returns {Issue[]} - Issues encountered in adding the definition.
+   */
+  addDefinitions(defs) {
+    const issues = []
+    for (const def of defs) {
+      issues.push(...this.addDefinition(def))
+    }
+    return issues
+  }
+
+  /**
+   * Add a Definition object to this manager
+   * @param {Definition} definition - The definition to be added.
+   * @returns {Issue[]}
+   */
+  addDefinition(definition) {
+    const lowerName = definition.name.toLowerCase()
+    const existingDefinition = this.definitions.get(lowerName)
+    if (existingDefinition && !existingDefinition.equivalent(definition)) {
+      return [
+        generateIssue('conflictingDefinitions', {
+          definition1: definition.defTag.originalTag,
+          definition2: existingDefinition.defGroup.originalTag,
+        }),
+      ]
+    }
+    if (!existingDefinition) {
+      this.definitions.set(lowerName, definition)
+    }
+    return []
+  }
+
+  /**
+   * Check the Def tags in a HED string for missing or incorrectly used Def tags.
+   * @param {ParsedHedString} hedString - A parsed HED string to be checked.
+   * @param {Schemas} hedSchemas - Schemas to validate against.
+   * @param {boolean} placeholderAllowed - If true then placeholder is allowed in the def tag.
+   * @returns {Issue[]} - If there is no matching definition or definition applied incorrectly.
+   */
+  validateDefs(hedString, hedSchemas, placeholderAllowed) {
+    const defTags = filterByTagName(hedString.tags, 'Def')
+    const issues = []
+    for (const tag of defTags) {
+      const defIssues = this.evaluateTag(tag, hedSchemas, placeholderAllowed)[1]
+      if (defIssues.length > 0) {
+        issues.push(...defIssues)
+      }
+    }
+    return issues
+  }
+
+  /**
+   * Check the Def tags in a HED string for missing or incorrectly used Def-expand tags.
+   * @param {ParsedHedString} hedString - A parsed HED string to be checked.
+   * @param {Schemas} hedSchemas - Schemas to validate against.
+   * @param {boolean} placeholderAllowed - If true then placeholder is allowed in the def tag.
+   * @returns {Issue[]} - If there is no matching definition or definition applied incorrectly.
+   */
+  validateDefExpands(hedString, hedSchemas, placeholderAllowed) {
+    //Def-expand tags should be rare, so don't look if there aren't any Def-expand tags
+    const defExpandTags = filterByTagName(hedString.tags, 'Def-expand')
+    if (defExpandTags.length === 0) {
+      return []
+    }
+    const issues = []
+    for (const topGroup of hedString.tagGroups) {
+      issues.push(...this._checkDefExpandGroup(topGroup, hedSchemas, placeholderAllowed))
+    }
+    return issues
+  }
+
+  /**
+   * Evaluate the definition based on a parsed HED tag.
+   * @param {ParsedHedTag} tag - The tag to evaluate against the definitions.
+   * @param {Schemas} hedSchemas - The schemas to be used to assist in the evaluation.
+   * @param {boolean} placeholderAllowed - If true then placeholder is allowed in the def tag.
+   * @returns {Array} - Returns [string, Issue[]] with definition contents for this tag and any issues.
+   *
+   * Note: If the tag is not a Def or Def-expand, this returns null for the string and [] for the issues.
+   */
+  evaluateTag(tag, hedSchemas, placeholderAllowed) {
+    const [definition, missingIssues] = this.findDefinition(tag)
+    if (missingIssues.length > 0) {
+      return [null, missingIssues]
+    } else if (definition) {
+      return definition.evaluateDefinition(tag, hedSchemas, placeholderAllowed)
+    }
+    return [null, []]
+  }
+
+  /**
+   * Recursively check for Def-expand groups in this group.
+   * @param {ParsedHedGroup} topGroup - a top group in a HED string to be evaluated for Def-expand groups.
+   * @param {Schemas} hedSchemas - The HED schemas to used in the check.
+   * @param {boolean} placeholderAllowed - If true then placeholder is allowed in the def tag.
+   * @returns {Issue[]}
+   * @private
+   */
+  _checkDefExpandGroup(topGroup, hedSchemas, placeholderAllowed) {
+    const issues = []
+    for (const group of topGroup.subParsedGroupIterator('Def-expand')) {
+      if (group.defExpandTags.length === 0) {
+        continue
+      }
+      // There should be only one Def-expand in this group as reserved requirements have been checked at parsing time.
+      const [normalizedValue, normalizedIssues] = this.evaluateTag(
+        group.defExpandTags[0],
+        hedSchemas,
+        placeholderAllowed,
+      )
+      issues.push(...normalizedIssues)
+      if (normalizedIssues.length > 0) {
+        continue
+      }
+      if (group.topGroups.length === 0 && normalizedValue !== '') {
+        issues.push(generateIssue('defExpandContentsInvalid', { contents: '', defContents: normalizedValue }))
+      } else if (group.topGroups.length > 0 && group.topGroups[0].normalized !== normalizedValue) {
+        issues.push(
+          generateIssue('defExpandContentsInvalid', {
+            contents: group.topGroups[0].normalized,
+            defContents: normalizedValue,
+          }),
+        )
+      }
+    }
+    return issues
+  }
+
+  /**
+   * Find the definition associated with a tag, if any
+   * @param {ParsedHedTag} tag - The parsed HEd tag to be checked.
+   * @returns {Array} -Returns [Definition, Issue[]]. If no match is found, the first element is null.
+   */
+  findDefinition(tag) {
+    if (tag.schemaTag._name !== 'Def' && tag.schemaTag.name !== 'Def-expand') {
+      return [null, []]
+    }
+    const name = tag._value.toLowerCase()
+    const existingDefinition = this.definitions.get(name)
+    const errorType = tag.schemaTag.name === 'Def' ? 'missingDefinitionForDef' : 'missingDefinitionForDefExpand'
+    if (!existingDefinition) {
+      return [null, [generateIssue(errorType, { definition: name })]]
+    }
+    if (!!existingDefinition.defTag._splitValue !== !!tag._splitValue) {
+      return [null, [generateIssue(errorType, { definition: name })]]
+    }
+    return [existingDefinition, []]
+  }
+
+  /**
+   * Create a list of Definition objects from a list of strings.
+   *
+   * @param {string[]} defStrings - A list of string definitions.
+   * @param {Schemas} hedSchemas - The HED schemas to use in creation.
+   * @returns {Array} - Returns [Definition[], Issue[]] with a definition list and any issues found.
+   */
+  static createDefinitions(defStrings, hedSchemas) {
+    const defList = []
+    const issues = []
+    for (const defString of defStrings) {
+      const [nextDef, defIssues] = Definition.createDefinition(defString, hedSchemas)
+      defList.push(nextDef)
+      issues.push(...defIssues)
+    }
+    return [defList, issues]
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_eventManager.js.html b/docs/html/parser_eventManager.js.html new file mode 100644 index 00000000..4a8d4815 --- /dev/null +++ b/docs/html/parser_eventManager.js.html @@ -0,0 +1,355 @@ + + + + + JSDoc: Source: parser/eventManager.js + + + + + + + + + +
+

Source: parser/eventManager.js

+ +
+
+
import { generateIssue } from '../issues/issues'
+import { BidsHedIssue } from '../bids'
+
+export class Event {
+  /**
+   * The name of the definition.
+   * @type {number}
+   */
+  onset
+
+  /**
+   * The parsed HED group representing the definition.
+   * @type {string}
+   */
+  defName
+
+  /**
+   * The short name of the tag representing this event ("Onset", "Inset", or "Offset").
+   * @type {string}
+   */
+  type
+
+  /**
+   * The parsed HED group representing the definition
+   * @type {ParsedHedGroup}
+   */
+  group
+
+  /**
+   * The tsv element source of this event.
+   * @type {BidsTsvElement}
+   */
+  element
+
+  constructor(defName, eventType, onset, group, element) {
+    this.defName = defName
+    this.type = eventType
+    this.onset = onset
+    this.group = group
+    this.file = element.file
+    this.tsvLine = element.tsvLine
+  }
+
+  /**
+   * Create an event from a ParsedHedGroup.
+   * @param {ParsedHedGroup} group - A group to extract an event from a temporal group, if it is a group.
+   * @param {BidsTsvElement} element - The element in which this group appears.
+   * @returns {Array} - Returns [Event, BidsHedIssue[]] representing the extracted event and issues.
+   */
+  static createEvent(group, element) {
+    if (group.requiresDefTag.length === 0) {
+      return [null, []]
+    }
+    let onset = Number(element.onset)
+    if (!Number.isFinite(onset)) {
+      return [
+        null,
+        [
+          BidsHedIssue.fromHedIssue(
+            generateIssue('temporalTagInNonTemporalContext', { string: element.hedString }),
+            element.file,
+            { tsvLine: element.tsvLine },
+          ),
+        ],
+      ]
+    }
+    onset = onset + Event.extractDelay(group)
+    const eventType = group.requiresDefTag[0].schemaTag.name
+    let defName = null
+    if (group.defTags.length === 1) {
+      defName = group.defTags[0]._remainder.toLowerCase()
+    } else if (group.defExpandChildren.length === 1) {
+      defName = group.defExpandChildren[0].topTags[0]._remainder.toLowerCase()
+    } else {
+      return [
+        null,
+        [
+          BidsHedIssue.fromHedIssue(
+            generateIssue('temporalWithWrongNumberDefs', { tagGroup: group.originalTag, tag: eventType }),
+            element.file,
+            { tsvLine: element.tsvLine },
+          ),
+        ],
+      ]
+    }
+    const event = new Event(defName, eventType, onset, group, element)
+    return [event, []]
+  }
+
+  static extractDelay(group) {
+    if (!group.reservedTags.has('Delay')) {
+      return 0
+    }
+    const tags = group.reservedTags.get('Delay')
+    const delay = Number(tags[0]._value)
+    return Number.isFinite(delay) ? delay : 0
+  }
+}
+
+export class EventManager {
+  static TOLERANCE = 1e-7
+  constructor() {}
+
+  /**
+   * Create a list of temporal events from BIDS elements.
+   * @param {BidsTsvElement[]} elements - The elements representing the contents of a tsv file.
+   * @returns {Array} - Returns [Event[], BidsHedIssue[]], the parsed event and any issues.
+   */
+  parseEvents(elements) {
+    const eventList = []
+    for (const element of elements) {
+      if (!element.parsedHedString) {
+        continue
+      }
+
+      for (const group of element.parsedHedString.tagGroups) {
+        const [event, eventIssues] = Event.createEvent(group, element)
+        if (eventIssues.length > 0) {
+          return [null, eventIssues]
+        }
+        if (event) {
+          eventList.push(event)
+        }
+      }
+    }
+    eventList.sort((a, b) => a.onset - b.onset)
+    return [eventList, []]
+  }
+
+  validate(eventList) {
+    const currentMap = new Map()
+    for (const event of eventList) {
+      if (!currentMap.has(event.defName)) {
+        if (event.type === 'Offset' || event.type === 'Inset') {
+          return [
+            BidsHedIssue.fromHedIssue(
+              generateIssue('inactiveOnset', { tag: event.type, definition: event.defName }),
+              event.file,
+              { tsvLine: event.tsvLine },
+            ),
+          ]
+        }
+        currentMap.set(event.defName, event)
+        continue
+      }
+      const issues = this._resolveConflicts(currentMap, event)
+      if (issues.length > 0) {
+        return issues
+      }
+    }
+    return []
+  }
+
+  _resolveConflicts(currentMap, event) {
+    const currentEvent = currentMap.get(event.defName)
+    // Make sure that these events are not at the same time
+    if (Math.abs(currentEvent.onset - event.onset) < EventManager.TOLERANCE) {
+      return [
+        BidsHedIssue.fromHedIssue(
+          generateIssue('simultaneousDuplicateEvents', {
+            tagGroup1: event.group.originalTag,
+            onset1: event.onset.toString(),
+            tsvLine1: event.tsvLine,
+            tagGroup2: currentEvent.group.originalTag,
+            onset2: currentEvent.onset.toString(),
+            tsvLine2: currentEvent.tsvLine,
+          }),
+          event.file,
+        ),
+      ]
+    }
+
+    if (event.type === 'Onset') {
+      currentMap.set(event.defName, event)
+    } else if (event.type === 'Inset' && currentEvent.type !== 'Offset') {
+      currentMap.set(event.defName, event)
+    } else if (event.type === 'Offset' && currentEvent.type !== 'Offset') {
+      currentMap.set(event.defName, event)
+    }
+
+    return []
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_parseUtils.js.html b/docs/html/parser_parseUtils.js.html new file mode 100644 index 00000000..10844180 --- /dev/null +++ b/docs/html/parser_parseUtils.js.html @@ -0,0 +1,263 @@ + + + + + JSDoc: Source: parser/parseUtils.js + + + + + + + + + +
+

Source: parser/parseUtils.js

+ +
+
+
import ParsedHedTag from './parsedHedTag'
+
+/**
+ * Extract the items of a specified subtype from a list of ParsedHedSubstring
+ * @param {ParsedHedSubstring[]} items - Objects to be filtered by class type.
+ * @param {Class} classType - The class type to filter by.
+ * @returns {ParsedHedSubstring[]} - A list of objects of the specified subclass of ParsedHedSubstring
+ */
+export function filterByClass(items, classType) {
+  return items && items.length ? items.filter((item) => item instanceof classType) : []
+}
+
+/**
+ * Extract the ParsedHedTag tags with a specified tag name
+ * @param {ParsedHedTag[]} tags - to be filtered by name
+ * @param {string} tagName - name of the tag to filter by
+ * @returns {ParsedHedTag[]}
+ */
+export function filterByTagName(tags, tagName) {
+  if (!tags) {
+    return []
+  }
+  return tags.filter((tag) => tag instanceof ParsedHedTag && tag.schemaTag?.name === tagName)
+}
+
+/**
+ * Extract the ParsedHedTag tags with a specified tag name.
+ * @param {Map<string, ParsedHedTag[]>} tagMap - The Map of parsed HED tags for extraction (must be defined).
+ * @param {string[]} tagNames - The names to use as keys for the filter.
+ * @returns {ParsedHedTag[]} - A list of temporal tags.
+ */
+export function filterTagMapByNames(tagMap, tagNames) {
+  if (!tagNames || tagMap.size === 0) {
+    return []
+  }
+
+  const keys = [...tagNames].filter((name) => tagMap.has(name))
+  if (keys.length === 0) {
+    return []
+  }
+
+  return keys.flatMap((key) => tagMap.get(key))
+}
+
+/**
+ * Convert a list of ParsedHedTag objects into a comma-separated string of their string representations.
+ * @param {ParsedHedTag[]} tagList - The HED tags whose string representations should be put in a comma-separated list.
+ * @returns {string} A comma separated list of original tag names for tags in tagList.
+ */
+export function getTagListString(tagList) {
+  return tagList.map((tag) => tag.toString()).join(', ')
+}
+
+/**
+ * Create a map of the ParsedHedTags by type.
+ * @param {ParsedHedTag[]} tagList - The HED tags to be categorized.
+ * @param {Set} tagNames - The tag names to use as categories.
+ * @returns {Map} - A map (string --> ParsedHedTag) of tag name to a list of tags with that name.
+ */
+export function categorizeTagsByName(tagList, tagNames = null) {
+  // Initialize the map with keys from tagNames and an "other" key
+  const resultMap = new Map()
+
+  // Iterate through A and categorize
+  tagList.forEach((tag) => {
+    if (!tagNames || tagNames.has(tag.schemaTag.name)) {
+      const tagList = resultMap.get(tag.schemaTag.name) || []
+      tagList.push(tag)
+      resultMap.set(tag.schemaTag.name, tagList) // Add to matching key list
+    }
+  })
+  return resultMap
+}
+
+/**
+ * Return a list of duplicate strings.
+ * @param { string[] } itemList - A list of strings to look for duplicates in.
+ * @returns {string[]} - A list of unique duplicate strings (multiple copies not repeated).
+ */
+export function getDuplicates(itemList) {
+  const checkSet = new Set()
+  const dupSet = new Set()
+  for (const item of itemList) {
+    if (!checkSet.has(item)) {
+      checkSet.add(item)
+    } else {
+      dupSet.add(item)
+    }
+  }
+  return [...dupSet]
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_parsedHedColumnSplice.js.html b/docs/html/parser_parsedHedColumnSplice.js.html new file mode 100644 index 00000000..beb1d942 --- /dev/null +++ b/docs/html/parser_parsedHedColumnSplice.js.html @@ -0,0 +1,212 @@ + + + + + JSDoc: Source: parser/parsedHedColumnSplice.js + + + + + + + + + +
+

Source: parser/parsedHedColumnSplice.js

+ +
+
+
import ParsedHedSubstring from './parsedHedSubstring'
+
+/**
+ * A template for an inline column splice in a {@link ParsedHedString} or {@link ParsedHedGroup}.
+ */
+export class ParsedHedColumnSplice extends ParsedHedSubstring {
+  /**
+   * Constructor.
+   *
+   * @param {string} columnName The token for this tag.
+   * @param {number[]} bounds The collection of HED schemas.
+   */
+  constructor(columnName, bounds) {
+    super(columnName, bounds) // Sets originalTag and originalBounds
+    this._normalized = this.format(false) // Sets various forms of the tag.
+  }
+
+  get normalized() {
+    {
+      return this._normalized
+    }
+  }
+
+  /**
+   * Nicely format this column splice template.
+   *
+   * @param {boolean} long Whether the tags should be in long form.
+   * @returns {string}
+   */
+  // eslint-disable-next-line no-unused-vars
+  format(long = true) {
+    return '{' + this.originalTag + '}'
+  }
+
+  equivalent(other) {
+    return other instanceof ParsedHedColumnSplice && this.originalTag === other.originalTag
+  }
+}
+
+export default ParsedHedColumnSplice
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_parsedHedGroup.js.html b/docs/html/parser_parsedHedGroup.js.html new file mode 100644 index 00000000..bdfd6225 --- /dev/null +++ b/docs/html/parser_parsedHedGroup.js.html @@ -0,0 +1,433 @@ + + + + + JSDoc: Source: parser/parsedHedGroup.js + + + + + + + + + +
+

Source: parser/parsedHedGroup.js

+ +
+
+
import differenceWith from 'lodash/differenceWith'
+import { IssueError } from '../issues/issues'
+import ParsedHedSubstring from './parsedHedSubstring'
+import ParsedHedTag from './parsedHedTag'
+import ParsedHedColumnSplice from './parsedHedColumnSplice'
+import { ReservedChecker } from './reservedChecker'
+import { filterByClass, categorizeTagsByName, getDuplicates, filterByTagName } from './parseUtils'
+
+/**
+ * A parsed HED tag group.
+ */
+export default class ParsedHedGroup extends ParsedHedSubstring {
+  /**
+   * The parsed HED tags, groups, or splices in the HED tag group at the top level.
+   * @type {ParsedHedSubstring[]}
+   */
+  tags
+
+  /**
+   * The top-level parsed HED tags in this string.
+   * @type {ParsedHedTag[]}
+   */
+  topTags
+
+  /**
+   * The top-level parsed HED groups in this string.
+   * @type {ParsedHedGroup[]}
+   */
+  topGroups
+
+  /**
+   * The top-level column splices in this string
+   * @type {ParsedHedColumnSplice[]}
+   */
+  topSplices
+
+  /**
+   * All the parsed HED tags in this string.
+   * @type {ParsedHedTag[]}
+   */
+  allTags
+
+  /**
+   * Reserved HED group tags. This only covers top group tags in the group.
+   * @type {Map<string, ParsedHedTag[]>}
+   */
+  reservedTags
+
+  /**
+   * The top-level child subgroups containing Def-expand tags.
+   * @type {ParsedHedGroup[]}
+   */
+  defExpandChildren
+
+  /**
+   * The top-level Def tags
+   * @type {ParsedHedTag[]}
+   */
+  defTags
+
+  /**
+   * The top-level Def-expand tags
+   * @type {ParsedHedTag[]}
+   */
+  defExpandTags
+
+  /**
+   * True if this group has a Definition tag at the top level.
+   * @type {boolean}
+   */
+  isDefinitionGroup
+
+  /**
+   * The total number of top-level Def tags and top-level Def-expand groups.
+   * @type {Number}
+   */
+  defCount
+
+  /**
+   * The unique top-level tag requiring a Def or Def-expand group, if any.
+   * @type {ParsedHedTag[] | null}
+   */
+  requiresDefTag
+
+  /**
+   * Constructor.
+   * @param {ParsedHedSubstring[]} parsedHedTags The parsed HED tags, groups or column splices in the HED tag group.
+   * @param {string} hedString The original HED string.
+   * @param {number[]} originalBounds The bounds of the HED tag in the original HED string.
+   */
+  constructor(parsedHedTags, hedString, originalBounds) {
+    const originalTag = hedString.substring(originalBounds[0], originalBounds[1])
+    super(originalTag, originalBounds)
+    this.tags = parsedHedTags
+    this.topGroups = filterByClass(parsedHedTags, ParsedHedGroup)
+    this.topTags = filterByClass(parsedHedTags, ParsedHedTag)
+    this.topSplices = filterByClass(parsedHedTags, ParsedHedColumnSplice)
+    this.allTags = this._getAllTags()
+    this._normalized = undefined
+    this._initializeGroups()
+  }
+
+  /**
+   * Recursively create a list of all the tags in this group.
+   * @returns {ParsedHedTag[]}
+   * @private
+   */
+  _getAllTags() {
+    const subgroupTags = this.topGroups.flatMap((tagGroup) => tagGroup.allTags)
+    return this.topTags.concat(subgroupTags)
+  }
+
+  /**
+   * Sets information about the reserved tags, particularly definition-related tags in this group.
+   * @private
+   */
+  _initializeGroups() {
+    const reserved = ReservedChecker.getInstance()
+    this.reservedTags = categorizeTagsByName(this.topTags, reserved.reservedNames)
+    this.defExpandTags = this._filterTopTagsByTagName('Def-expand')
+    this.definitionTags = this._filterTopTagsByTagName('Definition')
+    this.defExpandChildren = this._filterSubgroupsByTagName('Def-expand')
+    this.defTags = this._filterTopTagsByTagName('Def')
+    this.defCount = this.defTags.length + this.defExpandChildren.length
+    this.isDefinitionGroup = this.definitionTags.length > 0
+    this.requiresDefTag = [...this.reservedTags.entries()]
+      .filter((pair) => reserved.requiresDefTags.has(pair[0]))
+      .flatMap((pair) => pair[1]) // Flatten the values into a single list
+  }
+
+  /**
+   * Filter top tags by tag name.
+   *
+   * @param {string} tagName - The schemaTag name to filter by.
+   * @returns {Array} - An array of
+   * @private
+   *
+   */
+  _filterTopTagsByTagName(tagName) {
+    return this.topTags.filter((tag) => tag.schemaTag._name === tagName)
+  }
+
+  /**
+   * Filter top subgroups that include a tag at the top-level of the group.
+   *
+   * @param {string} tagName - The schemaTag name to filter by.
+   * @returns {Array} - Array of subgroups containing the specified tag.
+   * @private
+   */
+  _filterSubgroupsByTagName(tagName) {
+    return Array.from(this.topLevelGroupIterator()).filter((subgroup) =>
+      subgroup.topTags.some((tag) => tag.schemaTag.name === tagName),
+    )
+  }
+
+  /**
+   * Nicely format this tag group.
+   *
+   * @param {boolean} long Whether the tags should be in long form.
+   * @returns {string}
+   */
+  format(long = true) {
+    return '(' + this.tags.map((substring) => substring.format(long)).join(', ') + ')'
+  }
+
+  equivalent(other) {
+    if (!(other instanceof ParsedHedGroup)) {
+      return false
+    }
+    const equivalence = (ours, theirs) => ours.equivalent(theirs)
+    return (
+      differenceWith(this.tags, other.tags, equivalence).length === 0 &&
+      differenceWith(other.tags, this.tags, equivalence).length === 0
+    )
+  }
+
+  /**
+   * Return a normalized string representation
+   * @returns {string}
+   */
+  get normalized() {
+    if (this._normalized) {
+      return this._normalized
+    }
+    // Recursively normalize each item in the group
+    const normalizedItems = this.tags.map((item) => item.normalized)
+
+    // Sort normalized items to ensure order independence
+    const sortedNormalizedItems = normalizedItems.sort()
+
+    const duplicates = getDuplicates(sortedNormalizedItems)
+    if (duplicates.length > 0) {
+      IssueError.generateAndThrow('duplicateTag', {
+        tags: '[' + duplicates.join('],[') + ']',
+        string: this.originalTag,
+      })
+    }
+    this._normalized = '(' + sortedNormalizedItems.join(',') + ')'
+    // Return the normalized group as a string
+    return `(${sortedNormalizedItems.join(',')})` // Using curly braces to indicate unordered group
+  }
+
+  /**
+   * Iterator over the ParsedHedGroup objects in this HED tag group.
+   * @param {string | null} tagName - The name of the tag whose groups are to be iterated over or null if all tags.
+   * @yields {ParsedHedGroup} - This object and the ParsedHedGroup objects belonging to this tag group.
+   */
+  *subParsedGroupIterator(tagName = null) {
+    if (!tagName || filterByTagName(this.topTags, tagName)) {
+      yield this
+    }
+    for (const innerTag of this.tags) {
+      if (innerTag instanceof ParsedHedGroup) {
+        yield* innerTag.subParsedGroupIterator(tagName)
+      }
+    }
+  }
+
+  /**
+   * Iterator over the parsed HED tags in this HED tag group.
+   *
+   * @yields {ParsedHedTag} This tag group's HED tags.
+   */
+  *tagIterator() {
+    for (const innerTag of this.tags) {
+      if (innerTag instanceof ParsedHedTag) {
+        yield innerTag
+      } else if (innerTag instanceof ParsedHedGroup) {
+        yield* innerTag.tagIterator()
+      }
+    }
+  }
+
+  /**
+   * Iterator over the parsed HED column splices in this HED tag group.
+   *
+   * @yields {ParsedHedColumnSplice} This tag group's HED column splices.
+   */
+  *columnSpliceIterator() {
+    for (const innerTag of this.tags) {
+      if (innerTag instanceof ParsedHedColumnSplice) {
+        yield innerTag
+      } else if (innerTag instanceof ParsedHedGroup) {
+        yield* innerTag.columnSpliceIterator()
+      }
+    }
+  }
+
+  /**
+   * Iterator over the top-level parsed HED groups in this HED tag group.
+   *
+   * @yields {ParsedHedTag} This tag group's top-level HED groups.
+   */
+  *topLevelGroupIterator() {
+    for (const innerTag of this.tags) {
+      if (innerTag instanceof ParsedHedGroup) {
+        yield innerTag
+      }
+    }
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_parsedHedString.js.html b/docs/html/parser_parsedHedString.js.html new file mode 100644 index 00000000..41510f83 --- /dev/null +++ b/docs/html/parser_parsedHedString.js.html @@ -0,0 +1,286 @@ + + + + + JSDoc: Source: parser/parsedHedString.js + + + + + + + + + +
+

Source: parser/parsedHedString.js

+ +
+
+
import ParsedHedTag from './parsedHedTag'
+import ParsedHedGroup from './parsedHedGroup'
+import ParsedHedColumnSplice from './parsedHedColumnSplice'
+import { filterByClass, getDuplicates } from './parseUtils'
+import { IssueError } from '../issues/issues'
+
+/**
+ * A parsed HED string.
+ */
+export class ParsedHedString {
+  /**
+   * The original HED string.
+   * @type {string}
+   */
+  hedString
+  /**
+   * The parsed substring data in unfiltered form.
+   * @type {ParsedHedSubstring[]}
+   */
+  parseTree
+  /**
+   * The tag groups in the string (top-level).
+   * @type {ParsedHedGroup[]}
+   */
+  tagGroups
+  /**
+   * All the top-level tags in the string.
+   * @type {ParsedHedTag[]}
+   */
+  topLevelTags
+  /**
+   * All the tags in the string at all levels
+   * @type {ParsedHedTag[]}
+   */
+  tags
+  /**
+   * All the column splices in the string at all levels.
+   * @type {ParsedHedColumnSplice[]}
+   */
+  columnSplices
+  /**
+   * The tags in the top-level tag groups in the string, split into arrays.
+   * @type {ParsedHedTag[][]}
+   */
+  topLevelGroupTags
+  /**
+   * The top-level definition tag groups in the string.
+   * @type {ParsedHedGroup[]}
+   */
+  definitions
+
+  /**
+   * Constructor.
+   * @param {string} hedString The original HED string.
+   * @param {ParsedHedSubstring[]} parsedTags The nested list of parsed HED tags and groups.
+   */
+  constructor(hedString, parsedTags) {
+    this.hedString = hedString
+    this.parseTree = parsedTags
+    this.tagGroups = filterByClass(parsedTags, ParsedHedGroup)
+    this.topLevelTags = filterByClass(parsedTags, ParsedHedTag)
+
+    const subgroupTags = this.tagGroups.flatMap((tagGroup) => Array.from(tagGroup.tagIterator()))
+    this.tags = this.topLevelTags.concat(subgroupTags)
+
+    const topLevelColumnSplices = filterByClass(parsedTags, ParsedHedColumnSplice)
+    const subgroupColumnSplices = this.tagGroups.flatMap((tagGroup) => Array.from(tagGroup.columnSpliceIterator()))
+    this.columnSplices = topLevelColumnSplices.concat(subgroupColumnSplices)
+
+    //this.topLevelGroupTags = this.tagGroups.map((tagGroup) => filterByClass(tagGroup.tags, ParsedHedTag))
+    this.topLevelGroupTags = this.tagGroups.flatMap((tagGroup) => filterByClass(tagGroup.tags, ParsedHedTag))
+    this.definitions = this.tagGroups.filter((group) => group.isDefinitionGroup)
+    this.normalized = this._getNormalized()
+  }
+
+  /**
+   * Nicely format this HED string. (Doesn't allow column splices).
+   *
+   * @param {boolean} long Whether the tags should be in long form.
+   * @returns {string}
+   */
+  format(long = true) {
+    return this.parseTree.map((substring) => substring.format(long)).join(', ')
+  }
+
+  /**
+   * Return a normalized string representation
+   * @returns {string}
+   */
+  _getNormalized() {
+    // This is an implicit recursion as the items have the same call.
+    const normalizedItems = this.parseTree.map((item) => item.normalized)
+
+    // Sort normalized items to ensure order independence
+    const sortedNormalizedItems = normalizedItems.sort()
+    const duplicates = getDuplicates(sortedNormalizedItems)
+    if (duplicates.length > 0) {
+      IssueError.generateAndThrow('duplicateTag', { tags: '[' + duplicates.join('],[') + ']', string: this.hedString })
+    }
+    // Return the normalized group as a string
+    return `${sortedNormalizedItems.join(',')}` // Using curly braces to indicate unordered group
+  }
+
+  /**
+   * Override of {@link Object.prototype.toString}.
+   *
+   * @returns {string}
+   */
+  toString() {
+    return this.hedString
+  }
+}
+
+export default ParsedHedString
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_parsedHedSubstring.js.html b/docs/html/parser_parsedHedSubstring.js.html new file mode 100644 index 00000000..22990899 --- /dev/null +++ b/docs/html/parser_parsedHedSubstring.js.html @@ -0,0 +1,229 @@ + + + + + JSDoc: Source: parser/parsedHedSubstring.js + + + + + + + + + +
+

Source: parser/parsedHedSubstring.js

+ +
+
+
/**
+ * A parsed HED substring.
+ */
+export class ParsedHedSubstring {
+  /**
+   * The original pre-parsed version of the HED tag.
+   * @type {string}
+   */
+  originalTag
+  /**
+   * The bounds of the HED tag in the original HED string.
+   * @type {int[]}
+   */
+  originalBounds
+
+  /**
+   * Constructor.
+   * @param {string} originalTag The original HED tag.
+   * @param {number[]} originalBounds The bounds of the HED tag in the original HED string.
+   */
+  constructor(originalTag, originalBounds) {
+    this.originalTag = originalTag
+    this.originalBounds = originalBounds
+  }
+
+  /**
+   * Nicely format this substring. This is left blank for the subclasses to override.
+   *
+   * This is left blank for the subclasses to override.
+   *
+   * @param {boolean} long - Whether the tags should be in long form.
+   * @returns {string}
+   * @abstract
+   */
+  format(long = true) {}
+
+  /**
+   * Get the normalized version of the object.
+   *
+   * @returns {string}
+   * @abstract
+   */
+  get normalized() {
+    return ''
+  }
+
+  /**
+   * Override of {@link Object.prototype.toString}.
+   *
+   * @returns {string} The original form of this HED substring.
+   */
+  toString() {
+    return this.originalTag
+  }
+}
+
+export default ParsedHedSubstring
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_parsedHedTag.js.html b/docs/html/parser_parsedHedTag.js.html new file mode 100644 index 00000000..acd2107e --- /dev/null +++ b/docs/html/parser_parsedHedTag.js.html @@ -0,0 +1,508 @@ + + + + + JSDoc: Source: parser/parsedHedTag.js + + + + + + + + + +
+

Source: parser/parsedHedTag.js

+ +
+
+
import { IssueError } from '../issues/issues'
+import ParsedHedSubstring from './parsedHedSubstring'
+import { SchemaValueTag } from '../schema/entries'
+import TagConverter from './tagConverter'
+import { ReservedChecker } from './reservedChecker'
+
+const TWO_LEVEL_TAGS = new Set(['Definition', 'Def', 'Def-expand'])
+const allowedRegEx = /^[^{}\,]*$/
+
+/**
+ * A parsed HED tag.
+ */
+export default class ParsedHedTag extends ParsedHedSubstring {
+  /**
+   * The formatted canonical version of the HED tag.
+   * @type {string}
+   */
+  formattedTag
+
+  /**
+   * The canonical form of the HED tag.
+   * @type {string}
+   */
+  canonicalTag
+
+  /**
+   * The HED schema this tag belongs to.
+   * @type {Schema}
+   */
+
+  schema
+  /**
+   * The schema's representation of this tag.
+   *
+   * @type {SchemaTag}
+   * @private
+   */
+
+  _schemaTag
+
+  /**
+   * The remaining part of the tag after the portion actually in the schema.
+   * @type {string}
+   * @private
+   */
+  _remainder
+
+  /**
+   * The value of the tag, if any.
+   * @type {string}
+   * @private
+   */
+  _value
+
+  /**
+   * If definition, this is the second value, otherwise empty string.
+   * @type {string}
+   * @private
+   */
+  _splitValue
+
+  /**
+   * The units if any.
+   * @type {string}
+   * @private
+   */
+  _units
+
+  /**
+   * Constructor.
+   *
+   * @param {TagSpec} tagSpec The token for this tag.
+   * @param {Schemas} hedSchemas The collection of HED schemas.
+   * @param {string} hedString The original HED string.
+   * @throws {IssueError} If tag conversion or parsing fails.
+   */
+  constructor(tagSpec, hedSchemas, hedString) {
+    super(tagSpec.tag, tagSpec.bounds) // Sets originalTag and originalBounds
+    this._convertTag(hedSchemas, hedString, tagSpec)
+    this._normalized = this.format(false) // Sets various forms of the tag.
+  }
+
+  /**
+   * Convert this tag to its various forms
+   *
+   * @param {Schemas} hedSchemas The collection of HED schemas.
+   * @param {string} hedString The original HED string.
+   * @param {TagSpec} tagSpec The token for this tag.
+   * @throws {IssueError} If tag conversion or parsing fails.
+   */
+  _convertTag(hedSchemas, hedString, tagSpec) {
+    const schemaName = tagSpec.library
+    this.schema = hedSchemas.getSchema(schemaName)
+    if (this.schema === undefined) {
+      if (schemaName !== '') {
+        IssueError.generateAndThrow('unmatchedLibrarySchema', {
+          tag: this.originalTag,
+          library: schemaName,
+        })
+      } else {
+        IssueError.generateAndThrow('unmatchedBaseSchema', {
+          tag: this.originalTag,
+        })
+      }
+    }
+
+    const [schemaTag, remainder] = new TagConverter(tagSpec, hedSchemas).convert()
+    this._schemaTag = schemaTag
+    this._remainder = remainder
+    this.canonicalTag = this._schemaTag.longExtend(remainder)
+    this.formattedTag = this.canonicalTag.toLowerCase()
+    this._handleRemainder(schemaTag, remainder)
+  }
+
+  /**
+   * Handle the remainder portion for value tag (converter handles others).
+   *
+   * @param {SchemaTag} schemaTag - The part of the tag that is in the schema.
+   * @param {string} remainder - the leftover part.
+   * @throws {IssueError} If parsing the remainder section fails.
+   * @private
+   */
+  _handleRemainder(schemaTag, remainder) {
+    if (!(schemaTag instanceof SchemaValueTag)) {
+      return
+    }
+    // Check that there is a value if required
+    const reserved = ReservedChecker.getInstance()
+    if (
+      (schemaTag.hasAttributeName('requireChild') || reserved.requireValueTags.has(schemaTag.name)) &&
+      remainder === ''
+    ) {
+      IssueError.generateAndThrow('valueRequired', { tag: this.originalTag })
+    }
+    // Check if this could have a two-level value
+    const [value, rest] = this._getSplitValue(remainder)
+    this._splitValue = rest
+
+    // Resolve the units and check
+    const [actualUnit, actualUnitString, actualValueString] = this._separateUnits(schemaTag, value)
+    this._units = actualUnitString
+    this._value = actualValueString
+
+    if (actualUnit === null && actualUnitString !== null) {
+      IssueError.generateAndThrow('unitClassInvalidUnit', { tag: this.originalTag })
+    }
+    if (!this.checkValue(actualValueString)) {
+      IssueError.generateAndThrow('invalidValue', { tag: this.originalTag })
+    }
+  }
+
+  /**
+   * Separate the remainder of the tag into three parts.
+   *
+   * @param {SchemaTag} schemaTag - The part of the tag that is in the schema.
+   * @param {string} remainder - The leftover part.
+   * @returns {Array} - [SchemaUnit, string, string] representing the actual Unit, the unit string and the value string.
+   * @throws {IssueError} - If parsing the remainder section fails.
+   */
+  _separateUnits(schemaTag, remainder) {
+    const unitClasses = schemaTag.unitClasses
+    let actualUnit = null
+    let actualUnitString = null
+    let actualValueString = remainder // If no unit class, the remainder is the value
+    for (let i = 0; i < unitClasses.length; i++) {
+      ;[actualUnit, actualUnitString, actualValueString] = unitClasses[i].extractUnit(remainder)
+      if (actualUnit !== null) {
+        break // found the unit
+      }
+    }
+    return [actualUnit, actualUnitString, actualValueString]
+  }
+
+  /**
+   * Handle reserved three-level tags.
+   * @param {string} remainder - The remainder of the tag string after schema tag.
+   */
+  _getSplitValue(remainder) {
+    if (!TWO_LEVEL_TAGS.has(this.schemaTag.name)) {
+      return [remainder, null]
+    }
+    const [first, ...rest] = remainder.split('/')
+    return [first, rest.join('/')]
+  }
+
+  /**
+   * Nicely format this tag.
+   *
+   * @param {boolean} long - Whether the tags should be in long form.
+   * @returns {string} - The nicely formatted version of this tag.
+   */
+  format(long = true) {
+    let tagName
+    if (long) {
+      tagName = this._schemaTag?.longExtend(this._remainder)
+    } else {
+      tagName = this._schemaTag?.extend(this._remainder)
+    }
+    if (tagName === undefined) {
+      tagName = this.originalTag
+    }
+    if (this.schema?.prefix) {
+      return this.schema.prefix + ':' + tagName
+    } else {
+      return tagName
+    }
+  }
+
+  /**
+   * Return the normalized version of this tag.
+   * @returns {string} - The normalized version of this tag.
+   */
+  get normalized() {
+    return this._normalized
+  }
+
+  /**
+   * Override of {@link Object.prototype.toString}.
+   *
+   * @returns {string} The original form of this HED tag.
+   */
+  toString() {
+    if (this.schema?.prefix) {
+      return this.schema.prefix + ':' + this.originalTag
+    } else {
+      return this.originalTag
+    }
+  }
+
+  /**
+   * Determine whether this tag has a given attribute.
+   *
+   * @param {string} attribute An attribute name.
+   * @returns {boolean} Whether this tag has the named attribute.
+   */
+  hasAttribute(attribute) {
+    return this.schema?.tagHasAttribute(this.formattedTag, attribute)
+  }
+
+  /**
+   * Determine if this HED tag is equivalent to another HED tag.
+   *
+   * Note: HED tags are deemed equivalent if they have the same schema and normalized tag string.
+   *
+   * @param {ParsedHedTag} other - A HED tag to compare with this one.
+   * @returns {boolean} Whether {@link other} True, if other is equivalent to this HED tag.
+   */
+  equivalent(other) {
+    return other instanceof ParsedHedTag && this.formattedTag === other.formattedTag && this.schema === other.schema
+  }
+
+  /**
+   * Get the schema tag object for this tag.
+   *
+   * @returns {SchemaTag} The schema tag object for this tag.
+   */
+  get schemaTag() {
+    if (this._schemaTag instanceof SchemaValueTag) {
+      return this._schemaTag.parent
+    } else {
+      return this._schemaTag
+    }
+  }
+
+  /**
+   * Get the schema tag object for this tag's value-taking form.
+   *
+   * @returns {SchemaValueTag} The schema tag object for this tag's value-taking form.
+   */
+  get takesValueTag() {
+    if (this._schemaTag instanceof SchemaValueTag) {
+      return this._schemaTag
+    }
+    return undefined
+  }
+
+  /**
+   * Checks if this HED tag has the {@code takesValue} attribute.
+   *
+   * @returns {boolean} Whether this HED tag has the {@code takesValue} attribute.
+   */
+  get takesValue() {
+    return this.takesValueTag !== undefined
+  }
+
+  /**
+   * Checks if this HED tag has the {@code unitClass} attribute.
+   *
+   * @returns {boolean} Whether this HED tag has the {@code unitClass} attribute.
+   */
+  get hasUnitClass() {
+    if (!this.takesValueTag) {
+      return false
+    }
+    return this.takesValueTag.hasUnitClasses
+  }
+
+  /**
+   * Get the unit classes for this HED tag.
+   *
+   * @returns {SchemaUnitClass[]} The unit classes for this HED tag.
+   */
+  get unitClasses() {
+    if (this.hasUnitClass) {
+      return this.takesValueTag.unitClasses
+    }
+    return []
+  }
+
+  /**
+   * Check if value is a valid value for this tag.
+   *
+   * @param {string} value - The value to be checked.
+   * @returns {boolean} The result of check -- false if not a valid value.
+   */
+  checkValue(value) {
+    if (!this.takesValue) {
+      return false
+    }
+    if (value === '#') {
+      // Placeholders work
+      return true
+    }
+    const valueAttributeNames = this._schemaTag.valueAttributeNames
+    const valueClassNames = valueAttributeNames?.get('valueClass')
+    if (!valueClassNames) {
+      // No specified value classes
+      return allowedRegEx.test(value)
+    }
+    const entryManager = this.schema.entries.valueClasses
+    for (let i = 0; i < valueClassNames.length; i++) {
+      if (entryManager.getEntry(valueClassNames[i]).validateValue(value)) return true
+    }
+    return false
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_parser.js.html b/docs/html/parser_parser.js.html new file mode 100644 index 00000000..3a74b296 --- /dev/null +++ b/docs/html/parser_parser.js.html @@ -0,0 +1,338 @@ + + + + + JSDoc: Source: parser/parser.js + + + + + + + + + +
+

Source: parser/parser.js

+ +
+
+
import ParsedHedString from './parsedHedString'
+import HedStringSplitter from './splitter'
+import { generateIssue } from '../issues/issues'
+import { ReservedChecker } from './reservedChecker'
+import { DefinitionChecker } from './definitionChecker'
+
+/**
+ * A parser for HED strings.
+ */
+class HedStringParser {
+  /**
+   * The HED string being parsed.
+   * @type {string|ParsedHedString}
+   */
+  hedString
+
+  /**
+   * The collection of HED schemas.
+   * @type {Schemas}
+   */
+  hedSchemas
+
+  /**
+   * True if definitions are allowed in this string.
+   * @type {boolean}
+   */
+  definitionsAllowed
+
+  /**
+   * True if placeholders are allowed in this string.
+   * @type {boolean}
+   */
+  placeholdersAllowed
+
+  /**
+   * Constructor.
+   *
+   * @param {string|ParsedHedString} hedString - The HED string to be parsed.
+   * @param {Schemas} hedSchemas - The collection of HED schemas.
+   * @param {boolean} definitionsAllowed - True if definitions are allowed
+   * @param {boolean} placeholdersAllowed - True if placeholders are allowed
+   */
+  constructor(hedString, hedSchemas, definitionsAllowed, placeholdersAllowed) {
+    this.hedString = hedString
+    this.hedSchemas = hedSchemas
+    this.definitionsAllowed = definitionsAllowed
+    this.placeholdersAllowed = placeholdersAllowed
+  }
+
+  /**
+   * Parse a full HED string.
+   * @returns {Array} - [ParsedHedString|null, Issue[]] representing the parsed HED string and any parsing issues.
+   */
+  parseHedString() {
+    if (this.hedString === null || this.hedString === undefined) {
+      return [null, [generateIssue('invalidTagString', {})]]
+    }
+
+    const placeholderIssues = this._getPlaceholderCountIssues()
+    if (placeholderIssues.length > 0) {
+      return [null, placeholderIssues]
+    }
+    if (this.hedString instanceof ParsedHedString) {
+      return [this.hedString, []]
+    }
+    if (!this.hedSchemas) {
+      return [null, [generateIssue('missingSchemaSpecification', {})]]
+    }
+
+    // This assumes that splitter errors are only errors and not warnings
+    const [parsedTags, parsingIssues] = new HedStringSplitter(this.hedString, this.hedSchemas).splitHedString()
+    if (parsedTags === null || parsingIssues.length > 0) {
+      return [null, parsingIssues]
+    }
+
+    // Returns a parsed HED string unless empty
+    const parsedString = new ParsedHedString(this.hedString, parsedTags)
+    if (!parsedString) {
+      return [null, null]
+    }
+
+    // Check the definition syntax issues
+    const definitionIssues = new DefinitionChecker(parsedString).check(this.definitionsAllowed)
+    if (definitionIssues.length > 0) {
+      return [null, definitionIssues]
+    }
+
+    // Check the other reserved tags requirements
+    const checkIssues = ReservedChecker.getInstance().checkHedString(parsedString)
+    if (checkIssues.length > 0) {
+      return [null, checkIssues]
+    }
+    return [parsedString, []]
+  }
+
+  /**
+   * If placeholders are not allowed and the string has placeholders, return an issue.
+   * @returns {Issue[]} = Issues due to unwanted placeholders.
+   * @private
+   */
+  _getPlaceholderCountIssues() {
+    if (this.placeholdersAllowed) {
+      return []
+    }
+    const checkString = this.hedString instanceof ParsedHedString ? this.hedString.hedString : this.hedString
+    if (checkString.split('#').length > 1) {
+      return [generateIssue('invalidPlaceholderContext', { string: checkString })]
+    }
+    return []
+  }
+
+  /**
+   * Parse a list of HED strings.
+   *
+   * @param {string[]|ParsedHedString[]} hedStrings A list of HED strings.
+   * @param {Schemas} hedSchemas The collection of HED schemas.
+   * @param {boolean} definitionsAllowed - True if definitions are allowed
+   * @param {boolean} placeholdersAllowed - True if placeholders are allowed
+   * @returns {Array} - [ParsedHedString[], Issue[]] representing the parsed HED strings and any issues found.
+   */
+  static parseHedStrings(hedStrings, hedSchemas, definitionsAllowed, placeholdersAllowed) {
+    if (!hedSchemas) {
+      return [null, [generateIssue('missingSchemaSpecification', {})]]
+    }
+    const parsedStrings = []
+    const cumulativeIssues = []
+    for (const hedString of hedStrings) {
+      const [parsedString, currentIssues] = new HedStringParser(
+        hedString,
+        hedSchemas,
+        definitionsAllowed,
+        placeholdersAllowed,
+      ).parseHedString()
+      parsedStrings.push(parsedString)
+      cumulativeIssues.push(...currentIssues)
+    }
+
+    return [parsedStrings, cumulativeIssues]
+  }
+}
+
+/**
+ * Parse a HED string.
+ *
+ * @param {string|ParsedHedString} hedString A (possibly already parsed) HED string.
+ * @param {Schemas} hedSchemas - The collection of HED schemas.
+ * @param {boolean} definitionsAllowed - True if definitions are allowed.
+ * @param {boolean} placeholdersAllowed - True if placeholders are allowed.
+ * @returns {Array} - [ParsedHedString, Issue[]] representing the parsed HED string and any issues found.
+ */
+export function parseHedString(hedString, hedSchemas, definitionsAllowed, placeholdersAllowed) {
+  return new HedStringParser(hedString, hedSchemas, definitionsAllowed, placeholdersAllowed).parseHedString()
+}
+
+/**
+ * Parse a list of HED strings.
+ *
+ * @param {string[]|ParsedHedString[]} hedStrings - A list of HED strings.
+ * @param {Schemas} hedSchemas - The collection of HED schemas.
+ * @param {boolean} definitionsAllowed - True if definitions are allowed
+ * @param {boolean} placeholdersAllowed - True if placeholders are allowed
+ * @returns {Array} - [ParsedHedString[], Issue[]] representing the parsed HED strings and any issues found.
+ */
+export function parseHedStrings(hedStrings, hedSchemas, definitionsAllowed, placeholdersAllowed) {
+  return HedStringParser.parseHedStrings(hedStrings, hedSchemas, definitionsAllowed, placeholdersAllowed)
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_reservedChecker.js.html b/docs/html/parser_reservedChecker.js.html new file mode 100644 index 00000000..b4571c36 --- /dev/null +++ b/docs/html/parser_reservedChecker.js.html @@ -0,0 +1,470 @@ + + + + + JSDoc: Source: parser/reservedChecker.js + + + + + + + + + +
+

Source: parser/reservedChecker.js

+ +
+
+
import reservedTags from '../data/json/reservedTags.json'
+import { generateIssue } from '../issues/issues'
+import { getTagListString } from './parseUtils'
+
+export class ReservedChecker {
+  static instance = null
+  static reservedMap = new Map(Object.entries(reservedTags))
+
+  constructor() {
+    if (ReservedChecker.instance) {
+      throw new Error('Use ReservedChecker.getInstance() to get an instance of this class.')
+    }
+
+    this._initializeReservedTags()
+  }
+
+  // Static method to control access to the singleton instance
+  static getInstance() {
+    if (!ReservedChecker.instance) {
+      ReservedChecker.instance = new ReservedChecker()
+    }
+    return ReservedChecker.instance
+  }
+
+  _initializeReservedTags() {
+    this.reservedNames = new Set(ReservedChecker.reservedMap.keys())
+    this.requireValueTags = ReservedChecker._getReservedTagsByProperty('requireValue')
+    this.noExtensionTags = ReservedChecker._getReservedTagsByProperty('noExtension')
+    this.requiresDefTags = ReservedChecker._getReservedTagsByProperty('requiresDef')
+    this.timelineTags = ReservedChecker._getReservedTagsByProperty('requiresTimeline')
+  }
+
+  static _getReservedTagsByProperty(property) {
+    return new Set(
+      [...ReservedChecker.reservedMap.values()].filter((value) => value[property] === true).map((value) => value.name),
+    )
+  }
+
+  /**
+   * Perform syntactical checks on the provided HED string to detect violations.
+   *
+   * @param {ParsedHedString} hedString - The HED string to be checked.
+   * @returns {Issue[]} An array of issues if violations are found otherwise, an empty array.
+   */
+  checkHedString(hedString) {
+    const checks = [
+      () => this.checkUnique(hedString),
+      () => this.checkTagGroupLevels(hedString),
+      () => this.checkTopGroupRequirements(hedString),
+      () => this.checkNonTopGroups(hedString),
+    ]
+    for (const check of checks) {
+      const issues = check()
+      if (issues.length > 0) {
+        return issues
+      }
+    }
+    return []
+  }
+
+  /**
+   * Check for tags with the unique attribute.
+   *
+   * @param {ParsedHedString} hedString - The HED string to be checked for tags with the unique attribute.
+   * @returns {Issue[]} An array of `Issue` objects if there are violations; otherwise, an empty array.
+   */
+  checkUnique(hedString) {
+    const uniqueTags = hedString.tags.filter((tag) => tag.hasAttribute('unique'))
+    const uniqueNames = new Set()
+    for (const tag of uniqueTags) {
+      if (uniqueNames.has(tag.schemaTag._name)) {
+        return [generateIssue('multipleUniqueTags', { tag: tag.originalTag, string: hedString.hedString })]
+      }
+      uniqueNames.add(tag.schemaTag._name)
+    }
+    return []
+  }
+
+  /**
+   * Check whether tags are not in groups -- or top-level groups as required
+   *
+   * @param {ParsedHedString} hedString - The HED string to be checked for reserved tag syntax.
+   * @returns {Issue[]} An array of `Issue` objects if there are violations; otherwise, an empty array.
+   */
+  checkTagGroupLevels(hedString) {
+    const issues = []
+    const topGroupTags = hedString.topLevelGroupTags.flat()
+
+    // Check for top-level violations because tag is deep
+    hedString.tags.forEach((tag) => {
+      // If in a top group -- no problem regardless of tag group or top group attribute
+      if (topGroupTags.includes(tag)) {
+        return
+      }
+
+      // If this is a top tag group tag, we know it isn't in a top tag group.
+      if (ReservedChecker.hasTopLevelTagGroupAttribute(tag)) {
+        issues.push(generateIssue('invalidTopLevelTagGroupTag', { tag: tag.originalTag, string: hedString.hedString }))
+        return
+      }
+
+      // In final form --- if not in a group (not just a top group) but has the group tag attribute
+      if (hedString.topLevelTags.includes(tag) && ReservedChecker.hasGroupAttribute(tag)) {
+        issues.push(generateIssue('missingTagGroup', { tag: tag.originalTag, string: hedString.hedString }))
+      }
+    })
+    return issues
+  }
+
+  /**
+   * Check the group conditions of the reserved tags. The top-level has already been verified.
+   *
+   * @param {ParsedHedString} hedString - The HED string to check for group conflicts.
+   * @returns {Issue[]} An array of `Issue` objects if there are violations; otherwise, an empty array.
+   *
+   * Notes: These include the number of groups and top tag compatibility in the group
+   */
+  checkTopGroupRequirements(hedString) {
+    const issues = []
+    for (const group of hedString.tagGroups) {
+      const reservedTags = [...group.reservedTags.values()].flat()
+      for (const reservedTag of reservedTags) {
+        const nextIssues = this._checkGroupRequirements(group, reservedTag)
+        issues.push(...nextIssues)
+        // If an error is found in this group -- there is no point looking for more.
+        if (nextIssues.length > 0) {
+          break
+        }
+      }
+    }
+    return issues
+  }
+
+  /**
+   * Check the group tag requirements of a reserved Tag.
+   * @param {ParsedHedGroup} group - The group to check for tag requirements.
+   * @param {ParsedHedTag} reservedTag - A top-level reserved tag in group.
+   * @returns {Issue[]} - Returns an issue if the group requirements for this tag are not met.
+   */
+  _checkGroupRequirements(group, reservedTag) {
+    // Check that groups with tags that require a definition, have one.
+    if (group.requiresDefTag.length > 0 && group.defCount !== 1) {
+      return [
+        generateIssue('temporalWithWrongNumberDefs', { tag: group.requiresDefTag[0], tagGroup: group.originalTag }),
+      ]
+    }
+
+    const reservedRequirements = ReservedChecker.reservedMap.get(reservedTag.schemaTag.name)
+
+    // Check that only allowed tags are at the top level.
+    const issues = this._checkAllowedTags(group, reservedTag, reservedRequirements)
+    if (issues.length > 0) {
+      return issues
+    }
+    issues.push(...this._checkAllowedGroups(group, reservedTag, reservedRequirements))
+    return issues
+  }
+
+  /**
+   * Verify that the tags in the group are allowed with the reserved tag.
+   *
+   * @param {ParsedHedGroup} group - The enclosing tag group.
+   * @param {ParsedHedTag} reservedTag - The reserved tag whose tag requirements are to be checked.
+   * @param {Object} requirements - The requirements for this reserved tag.
+   * @returns {Issue[]} - Issues because
+   * @private
+   */
+  _checkAllowedTags(group, reservedTag, requirements) {
+    // The allowed tag requirement isn't applicable
+    if (requirements.otherAllowedNonDefTags === null || requirements.otherAllowedNonDefTags === undefined) {
+      return []
+    }
+    // Check for def or def-expand tags for a reserved tag that does not need them.
+    if (!requirements.requiresDef && group.requiresDefTag.length === 0 && group.defCount > 0) {
+      return [generateIssue('tooManyGroupTopTags', { string: group.originalTag })]
+    }
+
+    // Isolate the other top tags.
+    const otherTopTags = group.topTags.filter((tag) => tag !== reservedTag)
+    if (otherTopTags.length === 0) {
+      return []
+    }
+
+    const encountered = new Set()
+    for (const tag of otherTopTags) {
+      if (encountered.has(tag.schemaTag.name)) {
+        return [generateIssue('tooManyGroupTopTags', { string: group.originalTag })]
+      }
+      encountered.add(tag.schemaTag.name)
+      if (tag.schemaTag.name === 'Def' && group.requiresDefTag.length !== 0) {
+        continue
+      }
+      // This tag is not allowed with the reserved tag
+      if (!requirements.otherAllowedNonDefTags.includes(tag.schemaTag.name)) {
+        return [
+          generateIssue('invalidGroupTopTags', { tags: getTagListString(group.topTags), string: group.originalTag }),
+        ]
+      }
+    }
+    return []
+  }
+
+  /**
+   * Verify the group conditions are satisfied for a reserved tag.
+   *
+   * @param {ParsedHedGroup} group - The enclosing tag group.
+   * @param {ParsedHedTag} reservedTag - The reserved tag whose tag requirements are to be checked.
+   * @param {Object} requirements - The requirements for this reserved tag.
+   * @returns {Issue[]}
+   * @private
+   */
+  _checkAllowedGroups(group, reservedTag, requirements) {
+    // Proper Def and Def-expand count for a tag that requires a def is checked when group is created.
+    let defAdjustment = 0
+    if (group.defExpandChildren.length !== 0 && group.requiresDefTag.length > 0) {
+      defAdjustment = 1
+    }
+
+    // Check the group does not have more than the maximum allowed subgroups.
+    const maxLimit = requirements.maxNonDefSubgroups != null ? requirements.maxNonDefSubgroups : Infinity
+    if (group.topGroups.length - defAdjustment > maxLimit) {
+      return [generateIssue('invalidNumberOfSubgroups', { tag: reservedTag.originalTag, string: group.originalTag })]
+    }
+
+    // Check that the group has the correct minimum number of subgroups.
+    return this._checkMinGroupCount(group, reservedTag, requirements.minNonDefSubgroups, defAdjustment)
+  }
+
+  /**
+   * Verify that a group has the minimum required subgroups for its reserved tag.
+   * @param {ParsedHedGroup} group - The group to be checked.
+   * @param {ParsedHedTag} reservedTag - The reserved tags whose requirements are used.
+   * @param {Number | null} minLimit - The minimum number of non-def groups required or null if no requirement.
+   * @param {Number} defAdjustment - Either 0 or 1 depending on whether a def-expand is included.
+   * @returns {Issue[]} - Returns an issue list if the count requirement is violated.
+   * @private
+   */
+  _checkMinGroupCount(group, reservedTag, minLimit, defAdjustment) {
+    if (minLimit === null) {
+      return []
+    }
+    let nonEmptyGroups = 0
+    for (const subGroup of group.topGroups) {
+      if (subGroup.allTags.length > 0) {
+        nonEmptyGroups += 1
+      }
+    }
+    if (nonEmptyGroups < minLimit + defAdjustment) {
+      return [generateIssue('invalidNumberOfSubgroups', { tag: reservedTag.originalTag, string: group.originalTag })]
+    }
+
+    return []
+  }
+
+  /** Verify that there are no group tags at the top level of the string.
+   *
+   * @param {ParsedHedString} hedString - The HED string to be checked.
+   * @returns {Issue[]} - Returns issue list if there are top level tags that are group tags.
+   */
+  checkNonTopGroups(hedString) {
+    const group_tags = hedString.tags.filter(
+      (tag) => ReservedChecker.hasGroupAttribute(tag) && tag in hedString.topLevelTags,
+    )
+    if (group_tags.length > 0) {
+      return [generateIssue('missingTagGroup', { tag: getTagListString(group_tags) })]
+    }
+    return []
+  }
+
+  /**
+   * Indicate whether a tag should be a top-level tag.
+   *
+   * @param {ParsedHedTag} tag - HED tag to check for top-level requirements.
+   * @returns {boolean} If true, the tag is required to be at the top level.
+   *
+   * Note: This check both the reserved requirements and the 'topLevelTagGroup' attribute in the schema.
+   *
+   */
+  static hasTopLevelTagGroupAttribute(tag) {
+    return (
+      tag.schemaTag.hasAttributeName('topLevelTagGroup') ||
+      (ReservedChecker.reservedMap.has(tag.schemaTag.name) &&
+        ReservedChecker.reservedMap.get(tag.schemaTag.name).topLevelTagGroup)
+    )
+  }
+
+  /**
+   * Return a boolean indicating whether a tag is required to be in a tag group.
+   *
+   * @param {ParsedHedTag} tag - The HED tag to be checked.
+   * @returns {boolean} If true, this indicates that tag must be in a tag group.
+   *
+   * Note:  This checks both reserved and schema tag requirements.
+   */
+  static hasGroupAttribute(tag) {
+    return tag.schemaTag.hasAttributeName('tagGroup')
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_splitter.js.html b/docs/html/parser_splitter.js.html new file mode 100644 index 00000000..df910a27 --- /dev/null +++ b/docs/html/parser_splitter.js.html @@ -0,0 +1,294 @@ + + + + + JSDoc: Source: parser/splitter.js + + + + + + + + + +
+

Source: parser/splitter.js

+ +
+
+
import ParsedHedTag from './parsedHedTag'
+import ParsedHedColumnSplice from './parsedHedColumnSplice'
+import ParsedHedGroup from './parsedHedGroup'
+import { recursiveMap } from '../utils/array'
+import { HedStringTokenizer, ColumnSpliceSpec, TagSpec } from './tokenizer'
+import { generateIssue, IssueError } from '../issues/issues'
+
+export default class HedStringSplitter {
+  /**
+   * The HED string being split.
+   * @type {string}
+   */
+  hedString
+  /**
+   * The collection of HED schemas.
+   * @type {Schemas}
+   */
+  hedSchemas
+
+  issues
+
+  /**
+   * Constructor.
+   *
+   * @param {string} hedString The HED string to be split and parsed.
+   * @param {Schemas} hedSchemas The collection of HED schemas.
+   */
+  constructor(hedString, hedSchemas) {
+    this.hedString = hedString
+    this.hedSchemas = hedSchemas
+    this.issues = []
+  }
+
+  /**
+   * Split and parse a HED string into tags and groups.
+   *
+   * @returns {Array} - [ParsedHedSubstring[], Issue[]] representing the parsed HED string data and any issues found.
+   */
+  splitHedString() {
+    if (this.hedString === null || this.hedString === undefined || typeof this.hedString !== 'string') {
+      return [null, [generateIssue('invalidTagString', {})]]
+    }
+    if (this.hedString.length === 0) {
+      return [[], []]
+    }
+    const [tagSpecs, groupBounds, issues] = new HedStringTokenizer(this.hedString).tokenize()
+    if (issues.length > 0) {
+      return [null, issues]
+    }
+    const [parsedTags, parsingIssues] = this._createParsedTags(tagSpecs, groupBounds)
+    return [parsedTags, parsingIssues]
+  }
+
+  /**
+   * Create parsed HED tags and groups from specifications.
+   *
+   * @param {TagSpec[]} tagSpecs The tag specifications.
+   * @param {GroupSpec} groupSpecs The group specifications.
+   * @returns {Array} - [ParsedHedSubstring[], Issue[]] representing the parsed HED tags and any issues found.
+   */
+  _createParsedTags(tagSpecs, groupSpecs) {
+    // Create tags from specifications
+    this.issues = []
+    const parsedTags = recursiveMap((tagSpec) => this._createParsedTag(tagSpec), tagSpecs)
+
+    // Create groups from the parsed tags
+    const parsedTagsWithGroups = this._createParsedGroups(parsedTags, groupSpecs.children)
+    return [parsedTagsWithGroups, this.issues]
+  }
+
+  _createParsedTag(tagSpec) {
+    if (tagSpec instanceof TagSpec) {
+      try {
+        return new ParsedHedTag(tagSpec, this.hedSchemas, this.hedString)
+      } catch (issueError) {
+        this.issues.push(this._handleIssueError(issueError))
+        return null
+      }
+    } else if (tagSpec instanceof ColumnSpliceSpec) {
+      return new ParsedHedColumnSplice(tagSpec.columnName, tagSpec.bounds)
+    }
+  }
+
+  /**
+   * Handle any issue encountered during tag parsing.
+   *
+   * @param {Error|IssueError} issueError The error encountered.
+   */
+  _handleIssueError(issueError) {
+    if (issueError instanceof IssueError) {
+      return issueError.issue
+    } else if (issueError instanceof Error) {
+      return generateIssue('internalError', { message: issueError.message })
+    }
+  }
+
+  /**
+   * Create parsed HED groups from parsed tags and group specifications.
+   *
+   * @param {ParsedHedTag[]} tags The parsed HED tags.
+   * @param {GroupSpec[]} groupSpecs The group specifications.
+   * @returns {ParsedHedGroup[]} The parsed HED groups.
+   */
+  _createParsedGroups(tags, groupSpecs) {
+    const tagGroups = []
+    let index = 0
+
+    for (const tag of tags) {
+      if (Array.isArray(tag)) {
+        const groupSpec = groupSpecs[index]
+        tagGroups.push(
+          new ParsedHedGroup(this._createParsedGroups(tag, groupSpec.children), this.hedString, groupSpec.bounds),
+        )
+        index++
+      } else if (tag !== null) {
+        tagGroups.push(tag)
+      }
+    }
+
+    return tagGroups
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_tagConverter.js.html b/docs/html/parser_tagConverter.js.html new file mode 100644 index 00000000..b26d734c --- /dev/null +++ b/docs/html/parser_tagConverter.js.html @@ -0,0 +1,344 @@ + + + + + JSDoc: Source: parser/tagConverter.js + + + + + + + + + +
+

Source: parser/tagConverter.js

+ +
+
+
import { IssueError } from '../issues/issues'
+import { getTagSlashIndices } from '../utils/hedStrings'
+import { ReservedChecker } from './reservedChecker'
+
+/**
+ * Converter from a tag specification to a schema-based tag object.
+ */
+export default class TagConverter {
+  /**
+   * A parsed tag token.
+   * @type {TagSpec}
+   */
+  tagSpec
+
+  /**
+   * The tag string to convert.
+   * @type {string}
+   */
+  tagString
+
+  /**
+   * The tag string split by slashes.
+   * @type {string[]}
+   */
+  tagLevels
+
+  /**
+   * The indices of the tag string's slashes.
+   * @type {number[]}
+   */
+  tagSlashes
+
+  /**
+   * A HED schema collection.
+   * @type {Schemas}
+   */
+  hedSchemas
+
+  /**
+   * The entry manager for the tags in the active schema.
+   * @type {SchemaTagManager}
+   */
+  tagMapping
+
+  /**
+   * The converted tag in the schema.
+   * @type {SchemaTag}
+   */
+  schemaTag
+
+  /**
+   * The remainder (e.g. value, extension) of the tag string.
+   * @type {string}
+   */
+  remainder
+
+  /**
+   * Constructor.
+   *
+   * @param {TagSpec} tagSpec The tag specification to convert.
+   * @param {Schemas} hedSchemas The HED schema collection.
+   */
+  constructor(tagSpec, hedSchemas) {
+    this.hedSchemas = hedSchemas
+    this.tagMapping = hedSchemas.getSchema(tagSpec.library).entries.tags
+    this.tagSpec = tagSpec
+    this.tagString = tagSpec.tag
+    this.tagLevels = this.tagString.split('/')
+    this.tagSlashes = getTagSlashIndices(this.tagString)
+    this.remainder = undefined
+    this.special = ReservedChecker.getInstance()
+  }
+
+  /**
+   * Retrieve the {@link SchemaTag} object for a tag specification.
+   *
+   * @returns {Array} - [SchemaTag, string] representing schema's corresponding tag object and the remainder of the tag string.
+   * @throws {IssueError} If tag conversion.
+   */
+  convert() {
+    let parentTag = undefined
+    for (let tagLevelIndex = 0; tagLevelIndex < this.tagLevels.length; tagLevelIndex++) {
+      if (parentTag?.valueTag) {
+        // It is a value tag
+        this._setSchemaTag(parentTag.valueTag, tagLevelIndex)
+        return [this.schemaTag, this.remainder]
+      }
+      const childTag = this._validateChildTag(parentTag, tagLevelIndex)
+      if (childTag === undefined) {
+        // It is an extended tag and the rest is undefined
+        this._setSchemaTag(parentTag, tagLevelIndex)
+      }
+      parentTag = childTag
+    }
+    this._setSchemaTag(parentTag, this.tagLevels.length + 1) // Fix the ending
+    return [this.schemaTag, this.remainder]
+  }
+
+  _validateChildTag(parentTag, tagLevelIndex) {
+    const childTag = this._getSchemaTag(tagLevelIndex)
+    if (childTag === undefined) {
+      // This is an extended tag
+      if (tagLevelIndex === 0) {
+        // Top level tags can't be extensions
+        IssueError.generateAndThrow('invalidTag', { tag: this.tagString })
+      }
+      if (
+        parentTag !== undefined &&
+        (!parentTag.hasAttributeName('extensionAllowed') || this.special.noExtensionTags.has(parentTag.name))
+      ) {
+        IssueError.generateAndThrow('invalidExtension', {
+          tag: this.tagLevels[tagLevelIndex],
+          parentTag: this.tagLevels.slice(0, tagLevelIndex).join('/'),
+        })
+      }
+      this._checkExtensions(tagLevelIndex)
+      return childTag
+    }
+
+    if (tagLevelIndex > 0 && (childTag.parent === undefined || childTag.parent !== parentTag)) {
+      IssueError.generateAndThrow('invalidParentNode', {
+        tag: this.tagLevels[tagLevelIndex],
+        parentTag: this.tagLevels.slice(0, tagLevelIndex).join('/'),
+      })
+    }
+
+    return childTag
+  }
+
+  _checkExtensions(tagLevelIndex) {
+    // A non-tag has been detected --- from here on must be non-tags.
+    this._checkNameClass(tagLevelIndex) // This is an extension
+    for (let index = tagLevelIndex + 1; index < this.tagLevels.length; index++) {
+      const child = this._getSchemaTag(index)
+      if (child !== undefined) {
+        // A schema tag showed up after a non-schema tag
+        IssueError.generateAndThrow('invalidParentNode', {
+          tag: child.name,
+          parentTag: this.tagLevels.slice(0, index).join('/'),
+        })
+      }
+      this._checkNameClass(index)
+    }
+  }
+
+  _getSchemaTag(tagLevelIndex) {
+    const tagLevel = this.tagLevels[tagLevelIndex].toLowerCase()
+    return this.tagMapping.getEntry(tagLevel)
+  }
+
+  _setSchemaTag(schemaTag, remainderStartLevelIndex) {
+    if (this.schemaTag !== undefined) {
+      return
+    }
+    this.schemaTag = schemaTag
+    this.remainder = this.tagLevels.slice(remainderStartLevelIndex).join('/')
+    if (this.schemaTag?.hasAttributeName('requireChild') && !this.remainder) {
+      IssueError.generateAndThrow('childRequired', { tag: this.tagString })
+    }
+  }
+
+  _checkNameClass(index) {
+    // Check whether the tagLevel is a valid name class
+    const valueClasses = this.hedSchemas.getSchema(this.tagSpec.library).entries.valueClasses
+    if (!valueClasses._definitions.get('nameClass').validateValue(this.tagLevels[index])) {
+      IssueError.generateAndThrow('invalidExtension', {
+        tag: this.tagLevels[index],
+        parentTag: this.tagLevels.slice(0, index).join('/'),
+      })
+    }
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/parser_tokenizer.js.html b/docs/html/parser_tokenizer.js.html new file mode 100644 index 00000000..3e63795a --- /dev/null +++ b/docs/html/parser_tokenizer.js.html @@ -0,0 +1,573 @@ + + + + + JSDoc: Source: parser/tokenizer.js + + + + + + + + + +
+

Source: parser/tokenizer.js

+ +
+
+
import { unicodeName } from 'unicode-name'
+
+import { generateIssue } from '../issues/issues'
+
+const CHARACTERS = {
+  BLANK: ' ',
+  OPENING_GROUP: '(',
+  CLOSING_GROUP: ')',
+  OPENING_COLUMN: '{',
+  CLOSING_COLUMN: '}',
+  COMMA: ',',
+  COLON: ':',
+  SLASH: '/',
+  PLACEHOLDER: '#',
+}
+
+function getTrimmedBounds(originalString) {
+  const start = originalString.search(/\S/)
+
+  if (start === -1) {
+    // The string contains only whitespace
+    return null
+  }
+  const end = originalString.search(/\S\s*$/)
+  return [start, end + 1]
+}
+
+const invalidCharacters = new Set(['[', ']', '~', '"'])
+// Add control codes to invalidCharacters
+for (let i = 0x00; i <= 0x1f; i++) {
+  invalidCharacters.add(String.fromCodePoint(i))
+}
+for (let i = 0x7f; i <= 0x9f; i++) {
+  invalidCharacters.add(String.fromCodePoint(i))
+}
+
+/**
+ * A specification for a tokenized substring.
+ */
+export class SubstringSpec {
+  /**
+   * The starting and ending bounds of the substring.
+   * @type {number[]}
+   */
+  bounds
+
+  constructor(start, end) {
+    this.bounds = [start, end]
+  }
+}
+
+/**
+ * A specification for a tokenized tag.
+ */
+export class TagSpec extends SubstringSpec {
+  /**
+   * The tag this spec represents.
+   * @type {string}
+   */
+  tag
+
+  /**
+   * The schema prefix for this tag, if any.
+   * @type {string}
+   */
+  library
+
+  constructor(tag, start, end, librarySchema) {
+    super(start, end)
+
+    this.tag = tag.trim()
+    this.library = librarySchema
+  }
+}
+
+/**
+ * A specification for a tokenized tag group.
+ */
+export class GroupSpec extends SubstringSpec {
+  /**
+   * The child group specifications.
+   * @type {GroupSpec[]}
+   */
+  children
+
+  constructor(start, end, children) {
+    super(start, end)
+
+    this.children = children
+  }
+}
+
+/**
+ * A specification for a tokenized column splice template.
+ */
+export class ColumnSpliceSpec extends SubstringSpec {
+  /**
+   * The column name this spec refers to.
+   * @type {string}
+   */
+  columnName
+
+  constructor(name, start, end) {
+    super(start, end)
+
+    this.columnName = name.trim()
+  }
+}
+
+class TokenizerState {
+  constructor() {
+    this.currentToken = '' // Characters in the token currently being parsed
+    this.groupDepth = 0
+    this.startingIndex = 0 // Starting index of this token
+    this.lastDelimiter = [undefined, -1] // Type and position of the last delimiter
+    this.librarySchema = ''
+    this.lastSlash = -1 // Position of the last slash in current token
+    this.currentGroupStack = [[]]
+    this.parenthesesStack = []
+  }
+}
+
+/**
+ * Class for tokenizing HED strings.
+ */
+export class HedStringTokenizer {
+  constructor(hedString) {
+    this.hedString = hedString
+    this.issues = []
+    this.state = null
+  }
+
+  /**
+   * Split the HED string into delimiters and tags.
+   *
+   * @returns {Array} - [TagSpec[], GroupSpec, Issue[]] representing the tag specifications, group bounds, and any issues found.
+   */
+  tokenize() {
+    this.initializeTokenizer()
+    // Empty strings cannot be tokenized
+    if (this.hedString.trim().length === 0) {
+      this.pushIssue('emptyTagFound', 0)
+      return [[], null, this.issues]
+    }
+    for (let i = 0; i < this.hedString.length; i++) {
+      const character = this.hedString.charAt(i)
+      this.handleCharacter(i, character)
+      if (this.issues.length > 0) {
+        return [[], null, this.issues]
+      }
+    }
+    this.finalizeTokenizer()
+    if (this.issues.length > 0) {
+      return [[], null, this.issues]
+    } else {
+      return [this.state.currentGroupStack.pop(), this.state.parenthesesStack.pop(), []]
+    }
+  }
+
+  resetToken(i) {
+    this.state.startingIndex = i + 1
+    this.state.currentToken = ''
+    this.state.librarySchema = ''
+    this.state.lastSlash = '-1'
+  }
+
+  finalizeTokenizer() {
+    if (this.state.lastDelimiter[0] === CHARACTERS.OPENING_COLUMN) {
+      // Extra opening brace
+      this.pushIssue('unclosedCurlyBrace', this.state.lastDelimiter[1])
+    } else if (this.state.lastDelimiter[0] === CHARACTERS.OPENING_GROUP) {
+      // Extra opening parenthesis
+      this.pushIssue('unclosedParentheses', this.state.lastDelimiter[1])
+    } else if (
+      this.state.lastDelimiter[0] === CHARACTERS.COMMA &&
+      this.hedString.slice(this.state.lastDelimiter[1] + 1).trim().length === 0
+    ) {
+      this.pushIssue('emptyTagFound', this.state.lastDelimiter[1]) // Extra comma
+    } else if (this.state.lastSlash >= 0 && this.hedString.slice(this.state.lastSlash + 1).trim().length === 0) {
+      this.pushIssue('extraSlash', this.state.lastSlash) // Extra slash
+    }
+    if (
+      this.state.currentToken.trim().length > 0 &&
+      ![undefined, CHARACTERS.COMMA].includes(this.state.lastDelimiter[0])
+    ) {
+      // Missing comma
+      this.pushIssue('commaMissing', this.state.lastDelimiter[1] + 1)
+    } else {
+      if (this.state.currentToken.trim().length > 0) {
+        this.pushTag(this.hedString.length)
+      }
+      this.unwindGroupStack()
+    }
+  }
+
+  initializeTokenizer() {
+    this.issues = []
+    this.state = new TokenizerState()
+    this.state.parenthesesStack = [new GroupSpec(0, this.hedString.length, [])]
+  }
+
+  handleCharacter(i, character) {
+    const characterHandler = {
+      [CHARACTERS.OPENING_GROUP]: () => this.handleOpeningGroup(i),
+      [CHARACTERS.CLOSING_GROUP]: () => this.handleClosingGroup(i),
+      [CHARACTERS.OPENING_COLUMN]: () => this.handleOpeningColumn(i),
+      [CHARACTERS.CLOSING_COLUMN]: () => this.handleClosingColumn(i),
+      [CHARACTERS.COMMA]: () => this.handleComma(i),
+      [CHARACTERS.COLON]: () => this.handleColon(i),
+      [CHARACTERS.SLASH]: () => this.handleSlash(i),
+    }[character] // Selects the character handler based on the value of character
+
+    if (characterHandler) {
+      characterHandler()
+    } else if (invalidCharacters.has(character)) {
+      this.pushInvalidCharacterIssue(character, i)
+    } else {
+      this.state.currentToken += character
+    }
+  }
+
+  handleComma(i) {
+    const trimmed = this.hedString.slice(this.state.lastDelimiter[1] + 1, i).trim()
+    if (
+      [CHARACTERS.OPENING_GROUP, CHARACTERS.COMMA, undefined].includes(this.state.lastDelimiter[0]) &&
+      trimmed.length === 0
+    ) {
+      this.pushIssue('emptyTagFound', i) // Empty tag Ex: ",x" or "(, x" or "y, ,x"
+    } else if (this.state.lastDelimiter[0] === CHARACTERS.OPENING_COLUMN) {
+      this.pushIssue('unclosedCurlyBrace', this.state.lastDelimiter[1]) // Unclosed curly brace Ex: "{ x,"
+    }
+    if (
+      [CHARACTERS.CLOSING_GROUP, CHARACTERS.CLOSING_COLUMN].includes(this.state.lastDelimiter[0]) &&
+      trimmed.length > 0
+    ) {
+      // A tag followed a group or column with no comma Ex:  (x) yz
+      this.pushIssue('invalidTag', i, trimmed)
+    } else if (trimmed.length > 0) {
+      this.pushTag(i) // Tag has just finished
+    } else {
+      this.resetToken(i) // After a group or column
+    }
+    this.state.lastDelimiter = [CHARACTERS.COMMA, i]
+  }
+
+  handleSlash(i) {
+    if (this.state.currentToken.trim().length === 0) {
+      // Slash at beginning of tag.
+      this.pushIssue('extraSlash', i) // Slash at beginning of tag.
+    } else if (this.state.lastSlash >= 0 && this.hedString.slice(this.state.lastSlash + 1, i).trim().length === 0) {
+      this.pushIssue('extraSlash', i) // Slashes with only blanks between
+    } else if (i > 0 && this.hedString.charAt(i - 1) === CHARACTERS.BLANK) {
+      this.pushIssue('extraBlank', i - 1) // Blank before slash such as slash in value
+    } else if (i < this.hedString.length - 1 && this.hedString.charAt(i + 1) === CHARACTERS.BLANK) {
+      this.pushIssue('extraBlank', i + 1) //Blank after a slash
+    } else if (this.hedString.slice(i).trim().length === 0) {
+      this.pushIssue('extraSlash', this.state.startingIndex) // Extra slash at the end
+    } else {
+      this.state.currentToken += CHARACTERS.SLASH
+      this.state.lastSlash = i
+    }
+  }
+
+  handleOpeningGroup(i) {
+    if (this.state.lastDelimiter[0] === CHARACTERS.OPENING_COLUMN) {
+      this.pushIssue('unclosedCurlyBrace', this.state.lastDelimiter[1]) // After open curly brace Ex: "{  ("
+    } else if (this.state.lastDelimiter[0] === CHARACTERS.CLOSING_COLUMN) {
+      this.pushIssue('commaMissing', this.state.lastDelimiter[1]) // After close curly brace Ex: "} ("
+    } else if (this.state.lastDelimiter[0] === CHARACTERS.CLOSING_GROUP) {
+      this.pushIssue('commaMissing', this.state.lastDelimiter[1] + 1) // After close group Ex: ") ("
+    } else if (this.state.currentToken.trim().length > 0) {
+      this.pushInvalidTag('commaMissing', i, this.state.currentToken.trim()) // After tag Ex: "x ("
+    } else {
+      this.state.currentGroupStack.push([])
+      this.state.parenthesesStack.push(new GroupSpec(i, undefined, []))
+      this.resetToken(i)
+      this.state.groupDepth++
+      this.state.lastDelimiter = [CHARACTERS.OPENING_GROUP, i]
+    }
+  }
+
+  handleClosingGroup(i) {
+    if (this.state.groupDepth <= 0) {
+      this.pushIssue('unopenedParenthesis', i) // No corresponding opening group
+    } else if (this.state.lastDelimiter[0] === CHARACTERS.OPENING_COLUMN) {
+      this.pushIssue('unclosedCurlyBrace', this.state.lastDelimiter[1]) // After open curly brace Ex: "{ )"
+    } else {
+      if ([CHARACTERS.OPENING_GROUP, CHARACTERS.COMMA].includes(this.state.lastDelimiter[0])) {
+        // Should be a tag here
+        this.pushTag(i)
+      }
+      this.closeGroup(i) // Close the group by updating its bounds and moving it to the parent group.
+      this.state.lastDelimiter = [CHARACTERS.CLOSING_GROUP, i]
+    }
+  }
+
+  handleOpeningColumn(i) {
+    if (this.state.currentToken.trim().length > 0) {
+      this.pushInvalidCharacterIssue(CHARACTERS.OPENING_COLUMN, i) // Middle of a token Ex: "x {"
+    } else if (this.state.lastDelimiter[0] === CHARACTERS.OPENING_COLUMN) {
+      this.pushIssue('nestedCurlyBrace', i) // After open curly brace   Ex: "{x{"
+    } else {
+      this.state.lastDelimiter = [CHARACTERS.OPENING_COLUMN, i]
+    }
+  }
+
+  handleClosingColumn(i) {
+    if (this.state.lastDelimiter[0] !== CHARACTERS.OPENING_COLUMN) {
+      this.pushIssue('unopenedCurlyBrace', i) // No matching open brace Ex: " x}"
+    } else if (!this.state.currentToken.trim()) {
+      this.pushIssue('emptyCurlyBrace', i) // Column slice cannot be empty Ex: "{  }"
+    } else {
+      // Close column by updating bounds and moving it to the parent group, push a column splice on the stack.
+      this.state.currentGroupStack[this.state.groupDepth].push(
+        new ColumnSpliceSpec(this.state.currentToken.trim(), this.state.lastDelimiter[1], i),
+      )
+      this.resetToken(i)
+      this.state.lastDelimiter = [CHARACTERS.CLOSING_COLUMN, i]
+    }
+  }
+
+  handleColon(i) {
+    const trimmed = this.state.currentToken.trim()
+    if (this.state.librarySchema || trimmed.includes(CHARACTERS.BLANK) || trimmed.includes(CHARACTERS.SLASH)) {
+      this.state.currentToken += CHARACTERS.COLON // If colon has been seen or is part of a value.
+    } else if (/[^A-Za-z]/.test(trimmed)) {
+      this.pushIssue('invalidTagPrefix', i) // Prefix not alphabetic Ex:  "1a:xxx"
+    } else {
+      const lib = this.state.currentToken.trimStart()
+      this.resetToken(i)
+      this.state.librarySchema = lib
+    }
+  }
+
+  unwindGroupStack() {
+    while (this.state.groupDepth > 0) {
+      this.pushIssue(
+        'unclosedParenthesis',
+        this.state.parenthesesStack[this.state.parenthesesStack.length - 1].bounds[0],
+      )
+      this.closeGroup(this.hedString.length)
+    }
+  }
+
+  pushTag(i) {
+    if (this.state.currentToken.trim().length === 0) {
+      this.pushIssue('emptyTagFound', i)
+    } else if (this.checkForBadPlaceholderIssues(i)) {
+      this.pushInvalidTag('invalidPlaceholder', i, this.state.currentToken)
+    } else {
+      const bounds = getTrimmedBounds(this.state.currentToken)
+      this.state.currentGroupStack[this.state.groupDepth].push(
+        new TagSpec(
+          this.state.currentToken.trim(),
+          this.state.startingIndex + bounds[0],
+          this.state.startingIndex + bounds[1],
+          this.state.librarySchema,
+        ),
+      )
+      this.resetToken(i)
+    }
+  }
+
+  checkForBadPlaceholderIssues() {
+    const tokenSplit = this.state.currentToken.split(CHARACTERS.PLACEHOLDER)
+    if (tokenSplit.length === 1) {
+      // No placeholders to worry about for this tag
+      return false
+    }
+    return (
+      tokenSplit.length > 2 ||
+      !tokenSplit[0].endsWith(CHARACTERS.SLASH) || // A placeholder must be after a slash
+      (tokenSplit[1].trim().length > 0 && tokenSplit[1][0] !== CHARACTERS.BLANK)
+    )
+  }
+
+  closeGroup(i) {
+    const groupSpec = this.state.parenthesesStack.pop()
+    groupSpec.bounds[1] = i + 1
+    if (this.hedString.slice(groupSpec.bounds[0] + 1, i).trim().length === 0) {
+      this.pushIssue('emptyTagFound', i) //The group is empty
+    }
+    this.state.parenthesesStack[this.state.groupDepth - 1].children.push(groupSpec)
+    this.state.currentGroupStack[this.state.groupDepth - 1].push(this.state.currentGroupStack.pop())
+    this.state.groupDepth--
+  }
+
+  pushIssue(issueCode, index) {
+    this.issues.push(generateIssue(issueCode, { index, string: this.hedString }))
+  }
+
+  pushInvalidTag(issueCode, index, tag) {
+    this.issues.push(generateIssue(issueCode, { index, tag: tag, string: this.hedString }))
+  }
+
+  pushInvalidCharacterIssue(character, index) {
+    this.issues.push(
+      generateIssue('invalidCharacter', { character: unicodeName(character), index, string: this.hedString }),
+    )
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/schema_config.js.html b/docs/html/schema_config.js.html new file mode 100644 index 00000000..efd98c7f --- /dev/null +++ b/docs/html/schema_config.js.html @@ -0,0 +1,185 @@ + + + + + JSDoc: Source: schema/config.js + + + + + + + + + +
+

Source: schema/config.js

+ +
+
+
/** Bundled HED schema configuration. */
+
+export const localSchemaList = new Map([
+  ['HED8.0.0', require('../data/schemas/HED8.0.0.xml')],
+  ['HED8.1.0', require('../data/schemas/HED8.1.0.xml')],
+  ['HED8.2.0', require('../data/schemas/HED8.2.0.xml')],
+  ['HED8.3.0', require('../data/schemas/HED8.3.0.xml')],
+  ['HED_score_1.0.0', require('../data/schemas/HED_score_1.0.0.xml')],
+  ['HED_score_1.1.0', require('../data/schemas/HED_score_1.1.0.xml')],
+  ['HED_score_2.0.0', require('../data/schemas/HED_score_2.0.0.xml')],
+  ['HED_testlib_1.0.2', require('../data/schemas/HED_testlib_1.0.2.xml')],
+  ['HED_testlib_2.0.0', require('../data/schemas/HED_testlib_2.0.0.xml')],
+])
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/schema_containers.js.html b/docs/html/schema_containers.js.html new file mode 100644 index 00000000..2f8429b8 --- /dev/null +++ b/docs/html/schema_containers.js.html @@ -0,0 +1,396 @@ + + + + + JSDoc: Source: schema/containers.js + + + + + + + + + +
+

Source: schema/containers.js

+ +
+
+
import { getGenerationForSchemaVersion } from '../utils/hedData'
+
+/**
+ * An imported HED 3 schema.
+ */
+export class Schema {
+  /**
+   * The HED schema version.
+   * @type {string}
+   */
+  version
+  /**
+   * The HED generation of this schema.
+   * @type {Number}
+   */
+  generation
+  /**
+   * The HED library schema name.
+   * @type {string}
+   */
+  library
+  /**
+   * This schema's prefix in the active schema set.
+   * @type {string}
+   */
+  prefix
+  /**
+   * The collection of schema entries.
+   * @type {SchemaEntries}
+   */
+  entries
+  /**
+   * The standard HED schema version this schema is linked to.
+   * @type {string}
+   */
+  withStandard
+
+  /**
+   * Constructor.
+   *
+   * @param {object} xmlData The schema XML data.
+   * @param {SchemaEntries} entries A collection of schema entries.
+   */
+  constructor(xmlData, entries) {
+    const rootElement = xmlData.HED
+    this.version = rootElement?.$?.version
+    this.library = rootElement?.$?.library ?? ''
+
+    if (this.library) {
+      this.generation = 3
+    } else if (this.version) {
+      this.generation = getGenerationForSchemaVersion(this.version)
+    }
+
+    if (!this.library) {
+      this.withStandard = this.version
+    } else {
+      this.withStandard = xmlData.HED?.$?.withStandard
+    }
+    this.entries = entries
+  }
+
+  /**
+   * Determine if a HED tag has a particular attribute in this schema.
+   *
+   * @param {string} tag The HED tag to check.
+   * @param {string} tagAttribute The attribute to check for.
+   * @returns {boolean} Whether this tag has this attribute.
+   */
+  tagHasAttribute(tag, tagAttribute) {
+    return this.entries.tagHasAttribute(tag, tagAttribute)
+  }
+}
+
+/**
+ * An imported lazy partnered HED 3 schema.
+ */
+export class PartneredSchema extends Schema {
+  /**
+   * The actual HED 3 schemas underlying this partnered schema.
+   * @type {Schema[]}
+   */
+  actualSchemas
+
+  /**
+   * Constructor.
+   *
+   * @param {Schema[]} actualSchemas The actual HED 3 schemas underlying this partnered schema.
+   */
+  constructor(actualSchemas) {
+    super({}, actualSchemas[0].entries)
+    this.actualSchemas = actualSchemas
+    this.withStandard = actualSchemas[0].withStandard
+    this.library = undefined
+    this.generation = 3
+  }
+}
+
+/**
+ * The collection of active HED schemas.
+ */
+export class Schemas {
+  /**
+   * The imported HED schemas.
+   *
+   * The empty string key ("") corresponds to the schema with no nickname,
+   * while other keys correspond to the respective nicknames.
+   *
+   * This field is null for syntax-only validation.
+   *
+   * @type {Map<string, Schema>|null}
+   */
+  schemas
+
+  /**
+   * Constructor.
+   * @param {Schema|Map<string, Schema>|null} schemas The imported HED schemas.
+   */
+  constructor(schemas) {
+    if (schemas === null || schemas instanceof Map) {
+      this.schemas = schemas
+    } else if (schemas instanceof Schema) {
+      this.schemas = new Map([['', schemas]])
+    } else {
+      throw new Error('Invalid type passed to Schemas constructor')
+    }
+    if (this.schemas) {
+      this._addNicknamesToSchemas()
+    }
+  }
+
+  _addNicknamesToSchemas() {
+    for (const [nickname, schema] of this.schemas) {
+      schema.prefix = nickname
+    }
+  }
+
+  /**
+   * Return the schema with the given nickname.
+   *
+   * @param {string} schemaName A nickname in the schema set.
+   * @returns {Schema} The schema object corresponding to that nickname.
+   */
+  getSchema(schemaName) {
+    return this.schemas?.get(schemaName)
+  }
+
+  /**
+   * The base schema, i.e. the schema with no nickname, if one is defined.
+   *
+   * @returns {Schema}
+   */
+  get baseSchema() {
+    return this.getSchema('')
+  }
+
+  /**
+   * The standard schema, i.e. primary schema implementing the HED standard, if one is defined.
+   *
+   * @returns {Schema}
+   */
+  get standardSchema() {
+    if (this.schemas === null) {
+      return undefined
+    }
+    for (const schema of this.schemas.values()) {
+      if (schema.library === '') {
+        return schema
+      }
+    }
+    return undefined
+  }
+
+  /**
+   * The library schemas, i.e. the schema with nicknames, if any are defined.
+   *
+   * @returns {Map<string, Schema>|null}
+   */
+  get librarySchemas() {
+    if (this.schemas !== null) {
+      const schemasCopy = new Map(this.schemas)
+      schemasCopy.delete('')
+      return schemasCopy
+    } else {
+      return null
+    }
+  }
+
+  /**
+   * The HED generation of this schema.
+   *
+   * If baseSchema is null, generation is set to 0.
+   * @type {Number}
+   */
+  get generation() {
+    if (this.schemas === null || this.schemas.size === 0) {
+      return 0
+    } else if (this.librarySchemas.size > 0) {
+      return 3
+    } else if (this.baseSchema) {
+      return this.baseSchema.generation
+    } else {
+      return 0
+    }
+  }
+
+  /**
+   * Whether this schema collection is for syntactic validation only.
+   * @returns {boolean}
+   */
+  get isSyntaxOnly() {
+    return this.generation === 0
+  }
+
+  /**
+   * Whether this schema collection comprises HED 3 schemas.
+   * @returns {boolean}
+   */
+  get isHed3() {
+    return this.generation === 3
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/schema_entries.js.html b/docs/html/schema_entries.js.html new file mode 100644 index 00000000..1ed383da --- /dev/null +++ b/docs/html/schema_entries.js.html @@ -0,0 +1,1157 @@ + + + + + JSDoc: Source: schema/entries.js + + + + + + + + + +
+

Source: schema/entries.js

+ +
+
+
import pluralize from 'pluralize'
+import Memoizer from '../utils/memoizer'
+import { IssueError } from '../issues/issues'
+
+pluralize.addUncountableRule('hertz')
+
+/**
+ * SchemaEntries class
+ */
+export class SchemaEntries extends Memoizer {
+  /**
+   * The schema's properties.
+   * @type {SchemaEntryManager<SchemaProperty>}
+   */
+  properties
+
+  /**
+   * The schema's attributes.
+   * @type {SchemaEntryManager<SchemaAttribute>}
+   */
+  attributes
+
+  /**
+   * The schema's value classes.
+   * @type {SchemaEntryManager<SchemaValueClass>}
+   */
+  valueClasses
+
+  /**
+   * The schema's unit classes.
+   * @type {SchemaEntryManager<SchemaUnitClass>}
+   */
+  unitClasses
+
+  /**
+   * The schema's unit modifiers.
+   * @type {SchemaEntryManager<SchemaUnitModifier>}
+   */
+  unitModifiers
+
+  /**
+   * The schema's tags.
+   * @type {SchemaTagManager}
+   */
+  tags
+
+  /**
+   * Constructor.
+   * @param {SchemaParser} schemaParser A constructed schema parser.
+   */
+  constructor(schemaParser) {
+    super()
+    this.properties = new SchemaEntryManager(schemaParser.properties)
+    this.attributes = new SchemaEntryManager(schemaParser.attributes)
+    this.valueClasses = schemaParser.valueClasses
+    this.unitClasses = schemaParser.unitClasses
+    this.unitModifiers = schemaParser.unitModifiers
+    this.tags = schemaParser.tags
+  }
+
+  /**
+   * Get a map of all of this schema's units.
+   */
+  get allUnits() {
+    return this._memoize('allUnits', () => {
+      const units = []
+      for (const unitClass of this.unitClasses.values()) {
+        const unitClassUnits = unitClass.units
+        units.push(...unitClassUnits)
+      }
+      return new Map(units)
+    })
+  }
+
+  /**
+   * Get the schema's SI unit modifiers.
+   * @returns {Map} - string --> SchemaUnitModifier.
+   */
+  get SIUnitModifiers() {
+    return this.unitModifiers.getEntriesWithBooleanAttribute('SIUnitModifier')
+  }
+
+  /**
+   * Get the schema's SI unit symbol modifiers.
+   * @returns {Map} - string --> SchemaUnitSymbolModifier.
+   */
+  get SIUnitSymbolModifiers() {
+    return this.unitModifiers.getEntriesWithBooleanAttribute('SIUnitSymbolModifier')
+  }
+
+  /**
+   * Determine if a HED tag has a particular attribute in this schema.
+   *
+   * @param {string} tag The HED tag to check.
+   * @param {string} tagAttribute The attribute to check for.
+   * @returns {boolean} Whether this tag has this attribute.
+   */
+  tagHasAttribute(tag, tagAttribute) {
+    if (!this.tags.hasLongNameEntry(tag)) {
+      return false
+    }
+    return this.tags.getLongNameEntry(tag).hasAttributeName(tagAttribute)
+  }
+}
+
+/**
+ * A manager of {@link SchemaEntry} objects.
+ *
+ * @template T
+ */
+export class SchemaEntryManager extends Memoizer {
+  /**
+   * The definitions managed by this entry manager.
+   * @type {Map<string, T>}
+   */
+  _definitions
+
+  /**
+   * Constructor.
+   *
+   * @param {Map<string, T>} definitions A map of schema entry definitions.
+   */
+  constructor(definitions) {
+    super()
+    this._definitions = definitions
+  }
+
+  /**
+   * Iterator over the entry manager's entries.
+   *
+   * @template T
+   * @returns {IterableIterator} - [string, T]
+   */
+  [Symbol.iterator]() {
+    return this._definitions.entries()
+  }
+
+  /**
+   * Iterator over the entry manager's keys.
+   *
+   * @returns {IterableIterator} - [string]
+   */
+  keys() {
+    return this._definitions.keys()
+  }
+
+  /**
+   * Iterator over the entry manager's keys.
+   *
+   * @returns {IterableIterator} - [T]
+   */
+  values() {
+    return this._definitions.values()
+  }
+
+  /**
+   * Determine whether the entry with the given name exists.
+   *
+   * @param {string} name The name of the entry.
+   * @return {boolean} Whether the entry exists.
+   */
+  hasEntry(name) {
+    return this._definitions.has(name)
+  }
+
+  /**
+   * Get the entry with the given name.
+   *
+   * @param {string} name - The name of the entry to retrieve.
+   * @returns {T} - The entry with that name.
+   */
+  getEntry(name) {
+    return this._definitions.get(name)
+  }
+
+  /**
+   * Get a collection of entries with the given boolean attribute.
+   *
+   * @param {string} booleanAttributeName - The name of boolean attribute to filter on.
+   * @returns {Map} - string->T representing a  collection of entries with that attribute.
+   */
+  getEntriesWithBooleanAttribute(booleanAttributeName) {
+    return this._memoize(booleanAttributeName, () => {
+      return this.filter(([_, v]) => {
+        return v.hasAttributeName(booleanAttributeName)
+      })
+    })
+  }
+
+  /**
+   * Filter the map underlying this manager.
+   *
+   * @param {function} fn -  ([string, T]): boolean specifying the filtering function.
+   * @returns {Map} - string->T representing a  collection of entries with that attribute.
+   */
+  filter(fn) {
+    return SchemaEntryManager._filterDefinitionMap(this._definitions, fn)
+  }
+
+  /**
+   * Filter a definition map.
+   *
+   * @template T
+   * @param {Map<string, T>} definitionMap The definition map.
+   * @param {function} fn -  ([string, T]):boolean specifying the filtering function.
+   * @returns {Map} - string->T representing the filtered definitions.
+   * @protected
+   */
+  static _filterDefinitionMap(definitionMap, fn) {
+    const pairArray = Array.from(definitionMap.entries())
+    return new Map(pairArray.filter((entry) => fn(entry)))
+  }
+
+  /**
+   * The number of entries in this collection.
+   *
+   * @returns {number} The number of entries in this collection.
+   */
+  get length() {
+    return this._definitions.size
+  }
+}
+
+/**
+ * A manager of {@link SchemaTag} objects.
+ *
+ * @extends {SchemaEntryManager<SchemaTag>}
+ */
+export class SchemaTagManager extends SchemaEntryManager {
+  /**
+   * The mapping of tags by long name.
+   * @type {Map<string, SchemaTag>}
+   */
+  _definitionsByLongName
+
+  /**
+   * Constructor.
+   *
+   * @param {Map<string, SchemaTag>} byShortName The mapping of tags by short name.
+   * @param {Map<string, SchemaTag>} byLongName The mapping of tags by long name.
+   */
+  constructor(byShortName, byLongName) {
+    super(byShortName)
+    this._definitionsByLongName = byLongName
+  }
+
+  /**
+   * Determine whether the tag with the given name exists.
+   *
+   * @param {string} longName - The long name of the tag.
+   * @returns {boolean} -True if the tag exists.
+   */
+  hasLongNameEntry(longName) {
+    return this._definitionsByLongName.has(longName)
+  }
+
+  /**
+   * Get the tag with the given name.
+   *
+   * @param {string} longName - The long name of the tag to retrieve.
+   * @returns {SchemaTag} - The tag with that name.
+   */
+  getLongNameEntry(longName) {
+    return this._definitionsByLongName.get(longName)
+  }
+
+  /**
+   * Filter the map underlying this manager using the long name.
+   *
+   * @param {function} fn - ([string, SchemaTag]): boolean specifying the filtering function.
+   * @returns {Map} - string --> SchemaTag representing the filtered map.
+   */
+  filterByLongName(fn) {
+    return SchemaEntryManager._filterDefinitionMap(this._definitionsByLongName, fn)
+  }
+}
+
+/**
+ * SchemaEntry class
+ */
+export class SchemaEntry extends Memoizer {
+  /**
+   * The name of this schema entry.
+   * @type {string}
+   */
+  _name
+
+  constructor(name) {
+    super()
+    this._name = name
+  }
+
+  /**
+   * The name of this schema entry.
+   * @returns {string}
+   */
+  get name() {
+    return this._name
+  }
+
+  /**
+   * Whether this schema entry has this attribute (by name).
+   *
+   * This method is a stub to be overridden in {@link SchemaEntryWithAttributes}.
+   *
+   * @param {string} attributeName The attribute to check for.
+   * @returns {boolean} Whether this schema entry has this attribute.
+   */
+  // eslint-disable-next-line no-unused-vars
+  hasAttributeName(attributeName) {
+    return false
+  }
+}
+
+// TODO: Switch back to class constant once upstream bug is fixed.
+const categoryProperty = 'categoryProperty'
+const typeProperty = 'typeProperty'
+const roleProperty = 'roleProperty'
+
+/**
+ * A schema property.
+ */
+export class SchemaProperty extends SchemaEntry {
+  /**
+   * The type of the property.
+   * @type {string}
+   */
+  _propertyType
+
+  constructor(name, propertyType) {
+    super(name)
+    this._propertyType = propertyType
+  }
+
+  /**
+   * Whether this property describes a schema category.
+   * @returns {boolean}
+   */
+  get isCategoryProperty() {
+    return this._propertyType === categoryProperty
+  }
+
+  /**
+   * Whether this property describes a data type.
+   * @returns {boolean}
+   */
+  get isTypeProperty() {
+    return this._propertyType === typeProperty
+  }
+
+  /**
+   * Whether this property describes a role.
+   * @returns {boolean}
+   */
+  get isRoleProperty() {
+    return this._propertyType === roleProperty
+  }
+}
+
+// Pseudo-properties
+
+// TODO: Switch back to class constant once upstream bug is fixed.
+export const nodeProperty = new SchemaProperty('nodeProperty', categoryProperty)
+export const schemaAttributeProperty = new SchemaProperty('schemaAttributeProperty', categoryProperty)
+const stringProperty = new SchemaProperty('stringProperty', typeProperty)
+
+/**
+ * A schema attribute.
+ */
+export class SchemaAttribute extends SchemaEntry {
+  /**
+   * The categories of elements this schema attribute applies to.
+   * @type {Set<SchemaProperty>}
+   */
+  _categoryProperties
+  /**
+   * The data type of this schema attribute.
+   * @type {SchemaProperty}
+   */
+  _typeProperty
+  /**
+   * The set of role properties for this schema attribute.
+   * @type {Set<SchemaProperty>}
+   */
+  _roleProperties
+
+  /**
+   * Constructor.
+   *
+   * @param {string} name The name of the schema attribute.
+   * @param {SchemaProperty[]} properties The properties assigned to this schema attribute.
+   */
+  constructor(name, properties) {
+    super(name, new Set(), new Map())
+
+    // Parse properties
+    const categoryProperties = properties.filter((property) => property?.isCategoryProperty)
+    this._categoryProperties = categoryProperties.length === 0 ? new Set([nodeProperty]) : new Set(categoryProperties)
+    const typeProperties = properties.filter((property) => property?.isTypeProperty)
+    this._typeProperty = typeProperties.length === 0 ? stringProperty : typeProperties[0]
+    this._roleProperties = new Set(properties.filter((property) => property?.isRoleProperty))
+  }
+
+  /**
+   * The categories of elements this schema attribute applies to.
+   * @returns {Set<SchemaProperty>|SchemaProperty|undefined}
+   */
+  get categoryProperty() {
+    switch (this._categoryProperties.size) {
+      case 0:
+        return undefined
+      case 1:
+        return Array.from(this._categoryProperties)[0]
+      default:
+        return this._categoryProperties
+    }
+  }
+
+  /**
+   * The data type property of this schema attribute.
+   * @returns {SchemaProperty}
+   */
+  get typeProperty() {
+    return this._typeProperty
+  }
+
+  /**
+   * The set of role properties for this schema attribute.
+   * @returns {Set<SchemaProperty>}
+   */
+  get roleProperties() {
+    return new Set(this._roleProperties)
+  }
+}
+
+/**
+ * SchemaEntryWithAttributes class
+ */
+class SchemaEntryWithAttributes extends SchemaEntry {
+  /**
+   * The set of boolean attributes this schema entry has.
+   * @type {Set<SchemaAttribute>}
+   */
+  booleanAttributes
+  /**
+   * The collection of value attributes this schema entry has.
+   * @type {Map<SchemaAttribute, *>}
+   */
+  valueAttributes
+  /**
+   * The set of boolean attribute names this schema entry has.
+   * @type {Set<string>}
+   */
+  booleanAttributeNames
+  /**
+   * The collection of value attribute names this schema entry has.
+   * @type {Map<string, *>}
+   */
+  valueAttributeNames
+
+  constructor(name, booleanAttributes, valueAttributes) {
+    super(name)
+    this.booleanAttributes = booleanAttributes
+    this.valueAttributes = valueAttributes
+    this._parseAttributeNames()
+  }
+
+  /**
+   * Create aliases of the attribute collections keyed on their names.
+   *
+   * @private
+   */
+  _parseAttributeNames() {
+    this.booleanAttributeNames = new Set()
+    for (const attribute of this.booleanAttributes) {
+      this.booleanAttributeNames.add(attribute.name)
+    }
+    this.valueAttributeNames = new Map()
+    for (const [attributeName, value] of this.valueAttributes) {
+      this.valueAttributeNames.set(attributeName.name, value)
+    }
+  }
+
+  /**
+   * Whether this schema entry has this attribute.
+   * @param {SchemaAttribute} attribute The attribute to check for.
+   * @returns {boolean} Whether this schema entry has this attribute.
+   */
+  hasAttribute(attribute) {
+    return this.booleanAttributes.has(attribute)
+  }
+
+  /**
+   * Retrieve the value of an attribute on this schema entry.
+   * @param {SchemaAttribute} attribute The attribute whose value should be returned.
+   * @param {boolean} alwaysReturnArray Whether to return a singleton array instead of a scalar value.
+   * @returns {*} The value of the attribute.
+   */
+  getAttributeValue(attribute, alwaysReturnArray = false) {
+    return SchemaEntryWithAttributes._getMapArrayValue(this.valueAttributes, attribute, alwaysReturnArray)
+  }
+
+  /**
+   * Whether this schema entry has this attribute (by name).
+   * @param {string} attributeName The attribute to check for.
+   * @returns {boolean} Whether this schema entry has this attribute.
+   */
+  hasAttributeName(attributeName) {
+    return this.booleanAttributeNames.has(attributeName)
+  }
+
+  /**
+   * Retrieve the value of an attribute (by name) on this schema entry.
+   * @param {string} attributeName The attribute whose value should be returned.
+   * @param {boolean} alwaysReturnArray Whether to return a singleton array instead of a scalar value.
+   * @returns {*} The value of the attribute.
+   */
+  getNamedAttributeValue(attributeName, alwaysReturnArray = false) {
+    return SchemaEntryWithAttributes._getMapArrayValue(this.valueAttributeNames, attributeName, alwaysReturnArray)
+  }
+
+  /**
+   * Return a map value, with a scalar being returned in lieu of a singleton array if alwaysReturnArray is false.
+   *
+   * @template K,V
+   * @param {Map<K,V>} map The map to search.
+   * @param {K} key A key in the map.
+   * @param {boolean} alwaysReturnArray Whether to return a singleton array instead of a scalar value.
+   * @returns {V|V[]} The value for the key in the passed map.
+   * @private
+   */
+  static _getMapArrayValue(map, key, alwaysReturnArray) {
+    const value = map.get(key)
+    if (!alwaysReturnArray && Array.isArray(value) && value.length === 1) {
+      return value[0]
+    } else {
+      return value
+    }
+  }
+}
+
+/**
+ * SchemaUnit class
+ */
+export class SchemaUnit extends SchemaEntryWithAttributes {
+  /**
+   * The legal derivatives of this unit.
+   * @type {string[]}
+   */
+  _derivativeUnits
+
+  /**
+   * Constructor.
+   *
+   * @param {string} name The name of the unit.
+   * @param {Set<SchemaAttribute>} booleanAttributes This unit's boolean attributes.
+   * @param {Map<SchemaAttribute, *>} valueAttributes This unit's key-value attributes.
+   * @param {SchemaEntryManager<SchemaUnitModifier>} unitModifiers The collection of unit modifiers.
+   */
+  constructor(name, booleanAttributes, valueAttributes, unitModifiers) {
+    super(name, booleanAttributes, valueAttributes)
+
+    this._derivativeUnits = [name]
+    if (!this.isSIUnit) {
+      this._pushPluralUnit()
+      return
+    }
+    if (this.isUnitSymbol) {
+      const SIUnitSymbolModifiers = unitModifiers.getEntriesWithBooleanAttribute('SIUnitSymbolModifier')
+      for (const modifierName of SIUnitSymbolModifiers.keys()) {
+        this._derivativeUnits.push(modifierName + name)
+      }
+    } else {
+      const SIUnitModifiers = unitModifiers.getEntriesWithBooleanAttribute('SIUnitModifier')
+      const pluralUnit = this._pushPluralUnit()
+      for (const modifierName of SIUnitModifiers.keys()) {
+        this._derivativeUnits.push(modifierName + name, modifierName + pluralUnit)
+      }
+    }
+  }
+
+  _pushPluralUnit() {
+    if (!this.isUnitSymbol) {
+      const pluralUnit = pluralize.plural(this._name)
+      this._derivativeUnits.push(pluralUnit)
+      return pluralUnit
+    }
+    return null
+  }
+
+  *derivativeUnits() {
+    for (const unit of this._derivativeUnits) {
+      yield unit
+    }
+  }
+
+  get isPrefixUnit() {
+    return this.hasAttributeName('unitPrefix')
+  }
+
+  get isSIUnit() {
+    return this.hasAttributeName('SIUnit')
+  }
+
+  get isUnitSymbol() {
+    return this.hasAttributeName('unitSymbol')
+  }
+
+  /**
+   * Determine if a value has this unit.
+   *
+   * @param {string} value -- either the whole value or the part after a blank (if not a prefix unit)
+   * @returns {boolean} Whether the value has these units.
+   */
+  validateUnit(value) {
+    if (value == null || value === '') {
+      return false
+    }
+    if (this.isPrefixUnit) {
+      return value.startsWith(this.name)
+    }
+
+    for (const dUnit of this.derivativeUnits()) {
+      if (value === dUnit) {
+        return true
+      }
+    }
+    return false
+  }
+}
+
+/**
+ * SchemaUnitClass class
+ */
+export class SchemaUnitClass extends SchemaEntryWithAttributes {
+  /**
+   * The units for this unit class.
+   * @type {Map<string, SchemaUnit>}
+   */
+  _units
+
+  /**
+   * Constructor.
+   *
+   * @param {string} name The name of this unit class.
+   * @param {Set<SchemaAttribute>} booleanAttributes The boolean attributes for this unit class.
+   * @param {Map<SchemaAttribute, *>} valueAttributes The value attributes for this unit class.
+   * @param {Map<string, SchemaUnit>} units The units for this unit class.
+   * @constructor
+   */
+  constructor(name, booleanAttributes, valueAttributes, units) {
+    super(name, booleanAttributes, valueAttributes)
+    this._units = units
+  }
+
+  /**
+   * Get the units for this unit class.
+   * @returns {Map<string, SchemaUnit>}
+   */
+  get units() {
+    return new Map(this._units)
+  }
+
+  /**
+   * Get the default unit for this unit class.
+   * @returns {SchemaUnit}
+   */
+  get defaultUnit() {
+    return this._units.get(this.getNamedAttributeValue('defaultUnits'))
+  }
+
+  /**
+   * Extracts the Unit class and remainder
+   * @returns {Array} [SchemaUnit, string, string] containing unit class, unit string, and value string
+   */
+  extractUnit(value) {
+    let actualUnit = null // The Unit class of the value
+    let actualValueString = null // The actual value part of the value
+    let actualUnitString = null
+    let lastPart = null
+    let firstPart = null
+    const index = value.indexOf(' ')
+    if (index !== -1) {
+      lastPart = value.slice(index + 1)
+      firstPart = value.slice(0, index)
+    } else {
+      // no blank -- there are no units
+      return [null, null, value]
+    }
+    actualValueString = firstPart
+    actualUnitString = lastPart
+    for (const unit of this._units.values()) {
+      if (!unit.isPrefixUnit && unit.validateUnit(lastPart)) {
+        // Checking if it is non-prefixed unit
+        actualValueString = firstPart
+        actualUnitString = lastPart
+        actualUnit = unit
+        break
+      } else if (!unit.isPrefixUnit) {
+        continue
+      }
+      if (!unit.validateUnit(firstPart)) {
+        // If it got here, can only be a prefix Unit
+        continue
+      } else {
+        actualUnit = unit
+        actualValueString = value.substring(unit.name.length + 1)
+        actualUnitString = unit.name
+        break
+      }
+    }
+    return [actualUnit, actualUnitString, actualValueString]
+  }
+}
+
+/**
+ * SchemaUnitModifier class
+ */
+export class SchemaUnitModifier extends SchemaEntryWithAttributes {
+  constructor(name, booleanAttributes, valueAttributes) {
+    super(name, booleanAttributes, valueAttributes)
+  }
+
+  get isSIUnitModifier() {
+    return this.hasAttributeName('SIUnitModifier')
+  }
+
+  get isSIUnitSymbolModifier() {
+    return this.hasAttributeName('SIUnitSymbolModifier')
+  }
+}
+
+/**
+ * SchemaValueClass class
+ */
+export class SchemaValueClass extends SchemaEntryWithAttributes {
+  /**
+   * The character class-based regular expression.
+   * @type {RegExp}
+   * @private
+   */
+  _charClassRegex
+  /**
+   * The "word form"-based regular expression.
+   * @type {RegExp}
+   * @private
+   */
+  _wordRegex
+
+  /**
+   * Constructor.
+   *
+   * @param {string} name The name of this value class.
+   * @param {Set<SchemaAttribute>} booleanAttributes The boolean attributes for this value class.
+   * @param {Map<SchemaAttribute, *>} valueAttributes The value attributes for this value class.
+   * @param {RegExp} charClassRegex The character class-based regular expression for this value class.
+   * @param {RegExp} wordRegex The "word form"-based regular expression for this value class.
+   */
+
+  constructor(name, booleanAttributes, valueAttributes, charClassRegex, wordRegex) {
+    super(name, booleanAttributes, valueAttributes)
+    this._charClassRegex = charClassRegex
+    this._wordRegex = wordRegex
+  }
+
+  /**
+   * Determine if a value is valid according to this value class.
+   *
+   * @param {string} value A HED value.
+   * @returns {boolean} Whether the value conforms to this value class.
+   */
+  validateValue(value) {
+    return this._wordRegex.test(value) && this._charClassRegex.test(value)
+  }
+}
+
+/**
+ * A tag in a HED schema.
+ */
+export class SchemaTag extends SchemaEntryWithAttributes {
+  /**
+   * This tag's parent tag.
+   * @type {SchemaTag}
+   * @private
+   */
+  _parent
+  /**
+   * This tag's unit classes.
+   * @type {SchemaUnitClass[]}
+   * @private
+   */
+  _unitClasses
+
+  /**
+   * This tag's value-classes
+   * @type {SchemaValueClass[]}
+   * @private
+   */
+  _valueClasses
+
+  /**
+   * This tag's value-taking child.
+   * @type {SchemaValueTag}
+   * @private
+   */
+  _valueTag
+
+  /**
+   * Constructor.
+   *
+   * @param {string} name The name of this tag.
+   * @param {Set<SchemaAttribute>} booleanAttributes The boolean attributes for this tag.
+   * @param {Map<SchemaAttribute, *>} valueAttributes The value attributes for this tag.
+   * @param {SchemaUnitClass[]} unitClasses The unit classes for this tag.
+   * @param {SchemaValueClass[]} valueClasses The value classes for this tag.
+   * @constructor
+   */
+  constructor(name, booleanAttributes, valueAttributes, unitClasses, valueClasses) {
+    super(name, booleanAttributes, valueAttributes)
+    this._unitClasses = unitClasses ?? []
+    this._valueClasses = valueClasses ?? []
+  }
+
+  /**
+   * This tag's unit classes.
+   * @type {SchemaUnitClass[]}
+   */
+  get unitClasses() {
+    return this._unitClasses.slice() // The slice prevents modification
+  }
+
+  /**
+   * Whether this tag has any unit classes.
+   * @returns {boolean}
+   */
+  get hasUnitClasses() {
+    return this._unitClasses.length !== 0
+  }
+
+  /**
+   * This tag's value classes.
+   * @type {SchemaValueClass[]}
+   */
+  get valueClasses() {
+    return this._valueClasses.slice()
+  }
+
+  /**
+   * Whether this tag has any value classes.
+   * @returns {boolean}
+   */
+  get hasValueClasses() {
+    return this._valueClasses.length !== 0
+  }
+
+  /**
+   * This tag's value-taking child tag.
+   * @returns {SchemaValueTag}
+   */
+  get valueTag() {
+    return this._valueTag
+  }
+
+  /**
+   * Set the tag's value-taking child tag.
+   * @param {SchemaValueTag} newValueTag The new value-taking child tag.
+   */
+  set valueTag(newValueTag) {
+    if (this._valueTag === undefined) {
+      this._valueTag = newValueTag
+    } else {
+      IssueError.generateAndThrow('internalError', {
+        message: `Attempted to set value tag for schema tag "${this.longName}" when it already has one.`,
+      })
+    }
+  }
+
+  /**
+   * This tag's parent tag.
+   * @type {SchemaTag}
+   */
+  get parent() {
+    return this._parent
+  }
+
+  /**
+   * Set the tag's parent tag.
+   * @param {SchemaTag} newParent The new parent tag.
+   */
+  set parent(newParent) {
+    if (this._parent === undefined) {
+      this._parent = newParent
+    } else {
+      IssueError.generateAndThrow('internalError', {
+        message: `Attempted to set parent for schema tag ${this.longName} when it already has one.`,
+      })
+    }
+  }
+
+  /**
+   * Return all of this tag's ancestors.
+   * @returns {Array}
+   */
+  get ancestors() {
+    return this._memoize('ancestors', () => {
+      if (this.parent) {
+        return [this.parent, ...this.parent.ancestors]
+      }
+      return []
+    })
+  }
+
+  /**
+   * This tag's long name.
+   * @returns {string}
+   */
+  get longName() {
+    const nameParts = this.ancestors.map((parentTag) => parentTag.name)
+    nameParts.reverse().push(this.name)
+    return nameParts.join('/')
+  }
+
+  /**
+   * Extend this tag's short name.
+   *
+   * @param {string} extension The extension.
+   * @returns {string} The extended short string.
+   */
+  extend(extension) {
+    if (extension) {
+      return this.name + '/' + extension
+    } else {
+      return this.name
+    }
+  }
+
+  /**
+   * Extend this tag's long name.
+   *
+   * @param {string} extension The extension.
+   * @returns {string} The extended long string.
+   */
+  longExtend(extension) {
+    if (extension) {
+      return this.longName + '/' + extension
+    } else {
+      return this.longName
+    }
+  }
+}
+
+/**
+ * A value-taking tag in a HED schema.
+ */
+export class SchemaValueTag extends SchemaTag {
+  /**
+   * This tag's long name.
+   * @returns {string}
+   */
+  get longName() {
+    const nameParts = this.ancestors.map((parentTag) => parentTag.name)
+    nameParts.reverse().push('#')
+    return nameParts.join('/')
+  }
+
+  /**
+   * Extend this tag's short name.
+   *
+   * @param {string} extension The extension.
+   * @returns {string} The extended short string.
+   */
+  extend(extension) {
+    return this.parent.extend(extension)
+  }
+
+  /**
+   * Extend this tag's long name.
+   *
+   * @param {string} extension The extension.
+   * @returns {string} The extended long string.
+   */
+  longExtend(extension) {
+    return this.parent.longExtend(extension)
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/schema_init.js.html b/docs/html/schema_init.js.html new file mode 100644 index 00000000..6ddc4f6f --- /dev/null +++ b/docs/html/schema_init.js.html @@ -0,0 +1,229 @@ + + + + + JSDoc: Source: schema/init.js + + + + + + + + + +
+

Source: schema/init.js

+ +
+
+
import zip from 'lodash/zip'
+
+import loadSchema from './loader'
+import { setParent } from '../utils/xml2js'
+
+import SchemaParser from './parser'
+import PartneredSchemaMerger from './schemaMerger'
+import { Schema, Schemas } from './containers'
+
+/**
+ * Build a single schema container object from an XML file.
+ *
+ * @param {object} xmlData The schema's XML data
+ * @returns {Schema} The HED schema object.
+ */
+const buildSchemaObject = function (xmlData) {
+  const rootElement = xmlData.HED
+  setParent(rootElement, null)
+  const schemaEntries = new SchemaParser(rootElement).parse()
+  return new Schema(xmlData, schemaEntries)
+}
+
+/**
+ * Build a single merged schema container object from one or more XML files.
+ *
+ * @param {object[]} xmlData The schemas' XML data.
+ * @returns {Schema} The HED schema object.
+ */
+const buildSchemaObjects = function (xmlData) {
+  const schemas = xmlData.map((data) => buildSchemaObject(data))
+  if (schemas.length === 1) {
+    return schemas[0]
+  }
+  const partneredSchemaMerger = new PartneredSchemaMerger(schemas)
+  return partneredSchemaMerger.mergeSchemas()
+}
+
+/**
+ * Build a schema collection object from a schema specification.
+ *
+ * @param {SchemasSpec} schemaSpecs The description of which schemas to use.
+ * @returns {Promise<Schemas>} The schema container object and any issues found.
+ */
+export async function buildSchemas(schemaSpecs) {
+  const schemaKeys = Array.from(schemaSpecs.data.keys())
+  /* Data format example:
+   * [[xmlData, ...], [xmlData, xmlData, ...], ...] */
+  const schemaXmlData = await Promise.all(
+    schemaKeys.map((k) => {
+      const specs = schemaSpecs.data.get(k)
+      return Promise.all(specs.map((spec) => loadSchema(spec)))
+    }),
+  )
+  const schemaObjects = schemaXmlData.map(buildSchemaObjects)
+  const schemas = new Map(zip(schemaKeys, schemaObjects))
+  return new Schemas(schemas)
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/schema_loader.js.html b/docs/html/schema_loader.js.html new file mode 100644 index 00000000..c291cfde --- /dev/null +++ b/docs/html/schema_loader.js.html @@ -0,0 +1,288 @@ + + + + + JSDoc: Source: schema/loader.js + + + + + + + + + +
+

Source: schema/loader.js

+ +
+
+
/** HED schema loading functions. */
+
+/* Imports */
+import xml2js from 'xml2js'
+
+import * as files from '../utils/files'
+import { IssueError } from '../issues/issues'
+
+import { localSchemaList } from './config'
+
+/**
+ * Load schema XML data from a schema version or path description.
+ *
+ * @param {SchemaSpec} schemaDef The description of which schema to use.
+ * @returns {Promise<Object>} The schema XML data.
+ * @throws {IssueError} If the schema could not be loaded.
+ */
+export default async function loadSchema(schemaDef = null) {
+  const xmlData = await loadPromise(schemaDef)
+  if (xmlData === null) {
+    IssueError.generateAndThrow('invalidSchemaSpecification', { spec: JSON.stringify(schemaDef) })
+  }
+  return xmlData
+}
+
+/**
+ * Choose the schema Promise from a schema version or path description.
+ *
+ * @param {SchemaSpec} schemaDef The description of which schema to use.
+ * @returns {Promise<Object>} The schema XML data.
+ * @throws {IssueError} If the schema could not be loaded.
+ */
+async function loadPromise(schemaDef) {
+  if (schemaDef === null) {
+    return null
+  } else if (schemaDef.localPath) {
+    return loadLocalSchema(schemaDef.localPath)
+  } else if (localSchemaList.has(schemaDef.localName)) {
+    return loadBundledSchema(schemaDef)
+  } else {
+    return loadRemoteSchema(schemaDef)
+  }
+}
+
+/**
+ * Load schema XML data from the HED GitHub repository.
+ *
+ * @param {SchemaSpec} schemaDef The standard schema version to load.
+ * @returns {Promise<object>} The schema XML data.
+ * @throws {IssueError} If the schema could not be loaded.
+ */
+function loadRemoteSchema(schemaDef) {
+  let url
+  if (schemaDef.library) {
+    url = `https://raw.githubusercontent.com/hed-standard/hed-schemas/refs/heads/main/library_schemas/${schemaDef.library}/hedxml/HED_${schemaDef.library}_${schemaDef.version}.xml`
+  } else {
+    url = `https://raw.githubusercontent.com/hed-standard/hed-schemas/refs/heads/main/standard_schema/hedxml/HED${schemaDef.version}.xml`
+  }
+  return loadSchemaFile(files.readHTTPSFile(url), 'remoteSchemaLoadFailed', { spec: JSON.stringify(schemaDef) })
+}
+
+/**
+ * Load schema XML data from a local file.
+ *
+ * @param {string} path The path to the schema XML data.
+ * @returns {Promise<object>} The schema XML data.
+ * @throws {IssueError} If the schema could not be loaded.
+ */
+function loadLocalSchema(path) {
+  return loadSchemaFile(files.readFile(path), 'localSchemaLoadFailed', { path: path })
+}
+
+/**
+ * Load schema XML data from a bundled file.
+ *
+ * @param {SchemaSpec} schemaDef The description of which schema to use.
+ * @returns {Promise<object>} The schema XML data.
+ * @throws {IssueError} If the schema could not be loaded.
+ */
+async function loadBundledSchema(schemaDef) {
+  try {
+    return parseSchemaXML(localSchemaList.get(schemaDef.localName))
+  } catch (error) {
+    const issueArgs = { spec: JSON.stringify(schemaDef), error: error.message }
+    IssueError.generateAndThrow('bundledSchemaLoadFailed', issueArgs)
+  }
+}
+
+/**
+ * Actually load the schema XML file.
+ *
+ * @param {Promise<string>} xmlDataPromise The Promise containing the unparsed XML data.
+ * @param {string} issueCode The issue code.
+ * @param {Object<string, string>} issueArgs The issue arguments passed from the calling function.
+ * @returns {Promise<object>} The parsed schema XML data.
+ * @throws {IssueError} If the schema could not be loaded.
+ */
+async function loadSchemaFile(xmlDataPromise, issueCode, issueArgs) {
+  try {
+    const data = await xmlDataPromise
+    return parseSchemaXML(data)
+  } catch (error) {
+    issueArgs.error = error.message
+    IssueError.generateAndThrow(issueCode, issueArgs)
+  }
+}
+
+/**
+ * Parse the schema XML data.
+ *
+ * @param {string} data The XML data.
+ * @returns {Promise<object>} The schema XML data.
+ */
+function parseSchemaXML(data) {
+  return xml2js.parseStringPromise(data, { explicitCharkey: true })
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/schema_parser.js.html b/docs/html/schema_parser.js.html new file mode 100644 index 00000000..30727993 --- /dev/null +++ b/docs/html/schema_parser.js.html @@ -0,0 +1,672 @@ + + + + + JSDoc: Source: schema/parser.js + + + + + + + + + +
+

Source: schema/parser.js

+ +
+
+
import flattenDeep from 'lodash/flattenDeep'
+import zip from 'lodash/zip'
+import semver from 'semver'
+
+// TODO: Switch require once upstream bugs are fixed.
+// import xpath from 'xml2js-xpath'
+// Temporary
+import * as xpath from '../utils/xpath'
+
+import {
+  nodeProperty,
+  SchemaAttribute,
+  schemaAttributeProperty,
+  SchemaEntries,
+  SchemaEntryManager,
+  SchemaProperty,
+  SchemaTag,
+  SchemaTagManager,
+  SchemaUnit,
+  SchemaUnitClass,
+  SchemaUnitModifier,
+  SchemaValueClass,
+  SchemaValueTag,
+} from './entries'
+import { IssueError } from '../issues/issues'
+
+import classRegex from '../data/json/classRegex.json'
+
+const lc = (str) => str.toLowerCase()
+
+export default class SchemaParser {
+  /**
+   * The root XML element.
+   * @type {Object}
+   */
+  rootElement
+  /**
+   * @type {Map<string, SchemaProperty>}
+   */
+  properties
+  /**
+   * @type {Map<string, SchemaAttribute>}
+   */
+  attributes
+  /**
+   * The schema's value classes.
+   * @type {SchemaEntryManager<SchemaValueClass>}
+   */
+  valueClasses
+  /**
+   * The schema's unit classes.
+   * @type {SchemaEntryManager<SchemaUnitClass>}
+   */
+  unitClasses
+  /**
+   * The schema's unit modifiers.
+   * @type {SchemaEntryManager<SchemaUnitModifier>}
+   */
+  unitModifiers
+  /**
+   * The schema's tags.
+   * @type {SchemaTagManager}
+   */
+  tags
+
+  constructor(rootElement) {
+    this.rootElement = rootElement
+    this._versionDefinitions = {
+      typeProperties: new Set(['boolProperty']),
+      categoryProperties: new Set([
+        'elementProperty',
+        'nodeProperty',
+        'schemaAttributeProperty',
+        'unitProperty',
+        'unitClassProperty',
+        'unitModifierProperty',
+        'valueClassProperty',
+      ]),
+      roleProperties: new Set(['recursiveProperty', 'isInheritedProperty', 'annotationProperty']),
+    }
+  }
+
+  parse() {
+    this.populateDictionaries()
+    return new SchemaEntries(this)
+  }
+
+  populateDictionaries() {
+    this.parseProperties()
+    this.parseAttributes()
+    this.parseUnitModifiers()
+    this.parseUnitClasses()
+    this.parseValueClasses()
+    this.parseTags()
+  }
+
+  getAllChildTags(parentElement, elementName = 'node', excludeTakeValueTags = true) {
+    if (excludeTakeValueTags && this.getElementTagName(parentElement) === '#') {
+      return []
+    }
+    const tagElementChildren = this.getElementsByName(elementName, parentElement)
+    const childTags = flattenDeep(
+      tagElementChildren.map((child) => this.getAllChildTags(child, elementName, excludeTakeValueTags)),
+    )
+    childTags.push(parentElement)
+    return childTags
+  }
+
+  getElementsByName(elementName = 'node', parentElement = this.rootElement) {
+    return xpath.find(parentElement, '//' + elementName)
+  }
+
+  getParentTagName(tagElement) {
+    const parentTagElement = tagElement.$parent
+    if (parentTagElement && parentTagElement.$parent) {
+      return this.getElementTagName(parentTagElement)
+    } else {
+      return ''
+    }
+  }
+
+  /**
+   * Extract the name of an XML element.
+   *
+   * NOTE: This method cannot be merged into {@link getElementTagValue} because it is used as a first-class object.
+   *
+   * @param {object} element An XML element.
+   * @returns {string} The name of the element.
+   */
+  getElementTagName(element) {
+    return element.name[0]._
+  }
+
+  /**
+   * Extract a value from an XML element.
+   *
+   * @param {object} element An XML element.
+   * @param {string} tagName The tag value to extract.
+   * @returns {string} The value of the tag in the element.
+   */
+  getElementTagValue(element, tagName) {
+    return element[tagName][0]._
+  }
+
+  /**
+   * Retrieve all the tags in the schema.
+   *
+   * @param {string} tagElementName The name of the tag element.
+   * @returns {Map<Object, string>} The tag names and XML elements.
+   */
+  getAllTags(tagElementName = 'node') {
+    const tagElements = xpath.find(this.rootElement, '//' + tagElementName)
+    const tags = tagElements.map((element) => this.getElementTagName(element))
+    return new Map(zip(tagElements, tags))
+  }
+
+  // Rewrite starts here.
+
+  parseProperties() {
+    const propertyDefinitions = this.getElementsByName('propertyDefinition')
+    this.properties = new Map()
+    for (const definition of propertyDefinitions) {
+      const propertyName = this.getElementTagName(definition)
+      if (this._versionDefinitions.categoryProperties?.has(propertyName)) {
+        this.properties.set(
+          propertyName,
+          // TODO: Switch back to class constant once upstream bug is fixed.
+          new SchemaProperty(propertyName, 'categoryProperty'),
+        )
+      } else if (this._versionDefinitions.typeProperties?.has(propertyName)) {
+        this.properties.set(
+          propertyName,
+          // TODO: Switch back to class constant once upstream bug is fixed.
+          new SchemaProperty(propertyName, 'typeProperty'),
+        )
+      } else if (this._versionDefinitions.roleProperties?.has(propertyName)) {
+        this.properties.set(
+          propertyName,
+          // TODO: Switch back to class constant once upstream bug is fixed.
+          new SchemaProperty(propertyName, 'roleProperty'),
+        )
+      }
+    }
+    this._addCustomProperties()
+  }
+
+  parseAttributes() {
+    const attributeDefinitions = this.getElementsByName('schemaAttributeDefinition')
+    this.attributes = new Map()
+    for (const definition of attributeDefinitions) {
+      const attributeName = this.getElementTagName(definition)
+      const propertyElements = definition.property
+      let properties
+      if (propertyElements === undefined) {
+        properties = []
+      } else {
+        properties = propertyElements.map((element) => this.properties.get(this.getElementTagName(element)))
+      }
+      this.attributes.set(attributeName, new SchemaAttribute(attributeName, properties))
+    }
+    this._addCustomAttributes()
+  }
+
+  _getValueClassChars(name) {
+    let classChars
+    if (Array.isArray(classRegex.class_chars[name]) && classRegex.class_chars[name].length > 0) {
+      classChars =
+        '^(?:' + classRegex.class_chars[name].map((charClass) => classRegex.char_regex[charClass]).join('|') + ')+$'
+    } else {
+      classChars = '^.+$' // Any non-empty line or string.
+    }
+    return new RegExp(classChars)
+  }
+
+  parseValueClasses() {
+    const valueClasses = new Map()
+    const [booleanAttributeDefinitions, valueAttributeDefinitions] = this._parseDefinitions('valueClass')
+    for (const [name, valueAttributes] of valueAttributeDefinitions) {
+      const booleanAttributes = booleanAttributeDefinitions.get(name)
+      //valueClasses.set(name, new SchemaValueClass(name, booleanAttributes, valueAttributes))
+      const charRegex = this._getValueClassChars(name)
+      const wordRegex = new RegExp(classRegex.class_words[name] ?? '^.+$')
+      valueClasses.set(name, new SchemaValueClass(name, booleanAttributes, valueAttributes, charRegex, wordRegex))
+    }
+    this.valueClasses = new SchemaEntryManager(valueClasses)
+  }
+
+  parseUnitModifiers() {
+    const unitModifiers = new Map()
+    const [booleanAttributeDefinitions, valueAttributeDefinitions] = this._parseDefinitions('unitModifier')
+    for (const [name, valueAttributes] of valueAttributeDefinitions) {
+      const booleanAttributes = booleanAttributeDefinitions.get(name)
+      unitModifiers.set(name, new SchemaUnitModifier(name, booleanAttributes, valueAttributes))
+    }
+    this.unitModifiers = new SchemaEntryManager(unitModifiers)
+  }
+
+  parseUnitClasses() {
+    const unitClasses = new Map()
+    const [booleanAttributeDefinitions, valueAttributeDefinitions] = this._parseDefinitions('unitClass')
+    const unitClassUnits = this.parseUnits()
+
+    for (const [name, valueAttributes] of valueAttributeDefinitions) {
+      const booleanAttributes = booleanAttributeDefinitions.get(name)
+      unitClasses.set(name, new SchemaUnitClass(name, booleanAttributes, valueAttributes, unitClassUnits.get(name)))
+    }
+    this.unitClasses = new SchemaEntryManager(unitClasses)
+  }
+
+  parseUnits() {
+    const unitClassUnits = new Map()
+    const unitClassElements = this.getElementsByName('unitClassDefinition')
+    const unitModifiers = this.unitModifiers
+    for (const element of unitClassElements) {
+      const elementName = this.getElementTagName(element)
+      const units = new Map()
+      unitClassUnits.set(elementName, units)
+      if (element.unit === undefined) {
+        continue
+      }
+      const [unitBooleanAttributeDefinitions, unitValueAttributeDefinitions] = this._parseAttributeElements(
+        element.unit,
+        this.getElementTagName,
+      )
+      for (const [name, valueAttributes] of unitValueAttributeDefinitions) {
+        const booleanAttributes = unitBooleanAttributeDefinitions.get(name)
+        units.set(name, new SchemaUnit(name, booleanAttributes, valueAttributes, unitModifiers))
+      }
+    }
+    return unitClassUnits
+  }
+
+  // Tag parsing
+
+  /**
+   * Parse the schema's tags.
+   */
+  parseTags() {
+    const tags = this.getAllTags()
+    const shortTags = this._getShortTags(tags)
+    const [booleanAttributeDefinitions, valueAttributeDefinitions] = this._parseAttributeElements(
+      tags.keys(),
+      (element) => shortTags.get(element),
+    )
+
+    const tagUnitClassDefinitions = this._processTagUnitClasses(shortTags, valueAttributeDefinitions)
+    this._processRecursiveAttributes(shortTags, booleanAttributeDefinitions)
+
+    const tagEntries = this._createSchemaTags(
+      booleanAttributeDefinitions,
+      valueAttributeDefinitions,
+      tagUnitClassDefinitions,
+    )
+
+    this._injectTagFields(tags, shortTags, tagEntries)
+
+    const longNameTagEntries = new Map()
+    for (const tag of tagEntries.values()) {
+      longNameTagEntries.set(lc(tag.longName), tag)
+    }
+
+    this.tags = new SchemaTagManager(tagEntries, longNameTagEntries)
+  }
+
+  /**
+   * Generate the map from tag elements to shortened tag names.
+   *
+   * @param {Map<Object, string>} tags The map from tag elements to tag strings.
+   * @returns {Map<Object, string>} The map from tag elements to shortened tag names.
+   * @private
+   */
+  _getShortTags(tags) {
+    const shortTags = new Map()
+    for (const tagElement of tags.keys()) {
+      const shortKey =
+        this.getElementTagName(tagElement) === '#'
+          ? this.getParentTagName(tagElement) + '-#'
+          : this.getElementTagName(tagElement)
+      shortTags.set(tagElement, shortKey)
+    }
+    return shortTags
+  }
+
+  /**
+   * Process unit classes in tags.
+   *
+   * @param {Map<Object, string>} shortTags The map from tag elements to shortened tag names.
+   * @param {Map<string, Map<SchemaAttribute, *>>} valueAttributeDefinitions The map from shortened tag names to their value schema attributes.
+   * @returns {Map<string, SchemaUnitClass[]>} The map from shortened tag names to their unit classes.
+   * @private
+   */
+  _processTagUnitClasses(shortTags, valueAttributeDefinitions) {
+    const tagUnitClassAttribute = this.attributes.get('unitClass')
+    const tagUnitClassDefinitions = new Map()
+
+    for (const tagName of shortTags.values()) {
+      const valueAttributes = valueAttributeDefinitions.get(tagName)
+      if (valueAttributes.has(tagUnitClassAttribute)) {
+        tagUnitClassDefinitions.set(
+          tagName,
+          valueAttributes.get(tagUnitClassAttribute).map((unitClassName) => {
+            return this.unitClasses.getEntry(unitClassName)
+          }),
+        )
+        valueAttributes.delete(tagUnitClassAttribute)
+      }
+    }
+
+    return tagUnitClassDefinitions
+  }
+
+  /**
+   * Process recursive schema attributes.
+   *
+   * @param {Map<Object, string>} shortTags The map from tag elements to shortened tag names.
+   * @param {Map<string, Set<SchemaAttribute>>} booleanAttributeDefinitions The map from shortened tag names to their boolean schema attributes. Passed by reference.
+   * @private
+   */
+  _processRecursiveAttributes(shortTags, booleanAttributeDefinitions) {
+    const recursiveAttributes = this._getRecursiveAttributes()
+
+    for (const [tagElement, tagName] of shortTags) {
+      for (const attribute of recursiveAttributes) {
+        if (booleanAttributeDefinitions.get(tagName).has(attribute)) {
+          for (const childTag of this.getAllChildTags(tagElement)) {
+            const childTagName = this.getElementTagName(childTag)
+            booleanAttributeDefinitions.get(childTagName).add(attribute)
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Create the {@link SchemaTag} objects.
+   *
+   * @param {Map<string, Set<SchemaAttribute>>} booleanAttributeDefinitions The map from shortened tag names to their boolean schema attributes.
+   * @param {Map<string, Map<SchemaAttribute, *>>} valueAttributeDefinitions The map from shortened tag names to their value schema attributes.
+   * @param {Map<string, SchemaUnitClass[]>} tagUnitClassDefinitions The map from shortened tag names to their unit classes.
+   * @returns {Map<string, SchemaTag>} The map from lowercase shortened tag names to their tag objects.
+   * @private
+   */
+  _createSchemaTags(booleanAttributeDefinitions, valueAttributeDefinitions, tagUnitClassDefinitions) {
+    const tagTakesValueAttribute = this.attributes.get('takesValue')
+    const tagEntries = new Map()
+
+    for (const [name, valueAttributes] of valueAttributeDefinitions) {
+      if (tagEntries.has(name)) {
+        IssueError.generateAndThrow('duplicateTagsInSchema')
+      }
+
+      const booleanAttributes = booleanAttributeDefinitions.get(name)
+      const unitClasses = tagUnitClassDefinitions.get(name)
+
+      if (booleanAttributes.has(tagTakesValueAttribute)) {
+        tagEntries.set(lc(name), new SchemaValueTag(name, booleanAttributes, valueAttributes, unitClasses))
+      } else {
+        tagEntries.set(lc(name), new SchemaTag(name, booleanAttributes, valueAttributes, unitClasses))
+      }
+    }
+
+    return tagEntries
+  }
+
+  /**
+   * Inject special tag fields into the {@link SchemaTag} objects.
+   *
+   * @param {Map<Object, string>} tags The map from tag elements to tag strings.
+   * @param {Map<Object, string>} shortTags The map from tag elements to shortened tag names.
+   * @param {Map<string, SchemaTag>} tagEntries The map from shortened tag names to tag objects.
+   * @private
+   */
+  _injectTagFields(tags, shortTags, tagEntries) {
+    for (const tagElement of tags.keys()) {
+      const tagName = shortTags.get(tagElement)
+      const parentTagName = shortTags.get(tagElement.$parent)
+
+      if (parentTagName) {
+        tagEntries.get(lc(tagName)).parent = tagEntries.get(lc(parentTagName))
+      }
+
+      if (this.getElementTagName(tagElement) === '#') {
+        tagEntries.get(lc(parentTagName)).valueTag = tagEntries.get(lc(tagName))
+      }
+    }
+  }
+
+  _parseDefinitions(category) {
+    const categoryTagName = category + 'Definition'
+    const definitionElements = this.getElementsByName(categoryTagName)
+
+    return this._parseAttributeElements(definitionElements, this.getElementTagName)
+  }
+
+  _parseAttributeElements(elements, namer) {
+    const booleanAttributeDefinitions = new Map()
+    const valueAttributeDefinitions = new Map()
+
+    for (const element of elements) {
+      const [booleanAttributes, valueAttributes] = this._parseAttributeElement(element)
+
+      const elementName = namer(element)
+      booleanAttributeDefinitions.set(elementName, booleanAttributes)
+      valueAttributeDefinitions.set(elementName, valueAttributes)
+    }
+
+    return [booleanAttributeDefinitions, valueAttributeDefinitions]
+  }
+
+  _parseAttributeElement(element) {
+    const booleanAttributes = new Set()
+    const valueAttributes = new Map()
+
+    const tagAttributes = element.attribute ?? []
+
+    for (const tagAttribute of tagAttributes) {
+      const attributeName = this.getElementTagName(tagAttribute)
+      if (tagAttribute.value === undefined) {
+        booleanAttributes.add(this.attributes.get(attributeName))
+        continue
+      }
+      const values = tagAttribute.value.map((value) => value._)
+      valueAttributes.set(this.attributes.get(attributeName), values)
+    }
+
+    return [booleanAttributes, valueAttributes]
+  }
+
+  _getRecursiveAttributes() {
+    const attributeArray = Array.from(this.attributes.values())
+    if (semver.lt(this.rootElement.$.version, '8.3.0')) {
+      return attributeArray.filter((attribute) =>
+        attribute.roleProperties.has(this.properties.get('isInheritedProperty')),
+      )
+    } else {
+      return attributeArray.filter(
+        (attribute) => !attribute.roleProperties.has(this.properties.get('annotationProperty')),
+      )
+    }
+  }
+
+  _addCustomAttributes() {
+    const isInheritedProperty = this.properties.get('isInheritedProperty')
+    const extensionAllowedAttribute = this.attributes.get('extensionAllowed')
+    if (this.rootElement.$.library === undefined && semver.lt(this.rootElement.$.version, '8.2.0')) {
+      extensionAllowedAttribute._roleProperties.add(isInheritedProperty)
+    }
+    const inLibraryAttribute = this.attributes.get('inLibrary')
+    if (inLibraryAttribute && semver.lt(this.rootElement.$.version, '8.3.0')) {
+      inLibraryAttribute._roleProperties.add(isInheritedProperty)
+    }
+  }
+
+  _addCustomProperties() {
+    if (this.rootElement.$.library === undefined && semver.lt(this.rootElement.$.version, '8.2.0')) {
+      const recursiveProperty = new SchemaProperty('isInheritedProperty', 'roleProperty')
+      this.properties.set('isInheritedProperty', recursiveProperty)
+    }
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/schema_schemaMerger.js.html b/docs/html/schema_schemaMerger.js.html new file mode 100644 index 00000000..fc75053f --- /dev/null +++ b/docs/html/schema_schemaMerger.js.html @@ -0,0 +1,341 @@ + + + + + JSDoc: Source: schema/schemaMerger.js + + + + + + + + + +
+

Source: schema/schemaMerger.js

+ +
+
+
import { IssueError } from '../issues/issues'
+import { SchemaTag, SchemaValueTag } from './entries'
+import { PartneredSchema } from './containers'
+
+export default class PartneredSchemaMerger {
+  /**
+   * The sources of data to be merged.
+   * @type {Schema[]}
+   */
+  sourceSchemas
+  /**
+   * The current source of data to be merged.
+   * @type {Schema}
+   */
+  currentSource
+  /**
+   * The destination of data to be merged.
+   * @type {PartneredSchema}
+   */
+  destination
+
+  /**
+   * Constructor.
+   *
+   * @param {Schema[]} sourceSchemas The sources of data to be merged.
+   */
+  constructor(sourceSchemas) {
+    this.sourceSchemas = sourceSchemas
+    this.destination = new PartneredSchema(sourceSchemas)
+    this._validate()
+  }
+
+  /**
+   * Pre-validate the partnered schemas.
+   * @private
+   */
+  _validate() {
+    if (!this.sourceSchemas.every((schema) => schema.generation === 3)) {
+      IssueError.generateAndThrow('internalConsistencyError', { message: 'Partnered schemas must be HED-3G schemas' })
+    }
+
+    for (const schema of this.sourceSchemas.slice(1)) {
+      if (schema.withStandard !== this.destination.withStandard) {
+        IssueError.generateAndThrow('differentWithStandard', {
+          first: schema.withStandard,
+          second: this.destination.withStandard,
+        })
+      }
+    }
+  }
+
+  /**
+   * Merge the lazy partnered schemas.
+   *
+   * @returns {PartneredSchema} The merged partnered schema.
+   */
+  mergeSchemas() {
+    for (const additionalSchema of this.sourceSchemas.slice(1)) {
+      this.currentSource = additionalSchema
+      this._mergeData()
+    }
+    return this.destination
+  }
+
+  /**
+   * The source schema's tag collection.
+   *
+   * @return {SchemaTagManager}
+   */
+  get sourceTags() {
+    return this.currentSource.entries.tags
+  }
+
+  /**
+   * The destination schema's tag collection.
+   *
+   * @returns {SchemaTagManager}
+   */
+  get destinationTags() {
+    return this.destination.entries.tags
+  }
+
+  /**
+   * Merge two lazy partnered schemas.
+   * @private
+   */
+  _mergeData() {
+    this._mergeTags()
+  }
+
+  /**
+   * Merge the tags from two lazy partnered schemas.
+   * @private
+   */
+  _mergeTags() {
+    for (const tag of this.sourceTags.values()) {
+      this._mergeTag(tag)
+    }
+  }
+
+  /**
+   * Merge a tag from one schema to another.
+   *
+   * @param {SchemaTag} tag The tag to copy.
+   * @private
+   */
+  _mergeTag(tag) {
+    if (!tag.getNamedAttributeValue('inLibrary')) {
+      return
+    }
+
+    const shortName = tag.name
+    if (this.destinationTags.hasEntry(shortName.toLowerCase())) {
+      IssueError.generateAndThrow('lazyPartneredSchemasShareTag', { tag: shortName })
+    }
+
+    const rootedTagShortName = tag.getNamedAttributeValue('rooted')
+    if (rootedTagShortName) {
+      const parentTag = tag.parent
+      if (parentTag?.name?.toLowerCase() !== rootedTagShortName?.toLowerCase()) {
+        IssueError.generateAndThrow('internalError', { message: `Node ${shortName} is improperly rooted.` })
+      }
+    }
+
+    this._copyTagToSchema(tag)
+  }
+
+  /**
+   * Copy a tag from one schema to another.
+   *
+   * @param {SchemaTag} tag The tag to copy.
+   * @private
+   */
+  _copyTagToSchema(tag) {
+    const booleanAttributes = new Set()
+    const valueAttributes = new Map()
+
+    for (const attribute of tag.booleanAttributes) {
+      booleanAttributes.add(this.destination.entries.attributes.getEntry(attribute.name) ?? attribute)
+    }
+    for (const [key, value] of tag.valueAttributes) {
+      valueAttributes.set(this.destination.entries.attributes.getEntry(key.name) ?? key, value)
+    }
+
+    /**
+     * @type {SchemaUnitClass[]}
+     */
+    const unitClasses = tag.unitClasses.map(
+      (unitClass) => this.destination.entries.unitClasses.getEntry(unitClass.name) ?? unitClass,
+    )
+
+    let newTag
+    if (tag instanceof SchemaValueTag) {
+      newTag = new SchemaValueTag(tag.name, booleanAttributes, valueAttributes, unitClasses)
+    } else {
+      newTag = new SchemaTag(tag.name, booleanAttributes, valueAttributes, unitClasses)
+    }
+    const destinationParentTag = this.destinationTags.getEntry(tag.parent?.name?.toLowerCase())
+    if (destinationParentTag) {
+      newTag.parent = destinationParentTag
+      if (newTag instanceof SchemaValueTag) {
+        newTag.parent.valueTag = newTag
+      }
+    }
+
+    this.destinationTags._definitions.set(newTag.name.toLowerCase(), newTag)
+    this.destinationTags._definitionsByLongName.set(newTag.longName.toLowerCase(), newTag)
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/schema_specs.js.html b/docs/html/schema_specs.js.html new file mode 100644 index 00000000..c2aa4dea --- /dev/null +++ b/docs/html/schema_specs.js.html @@ -0,0 +1,272 @@ + + + + + JSDoc: Source: schema/specs.js + + + + + + + + + +
+

Source: schema/specs.js

+ +
+
+
/**
+ * A schema version specification.
+ */
+export class SchemaSpec {
+  /**
+   * The nickname of this schema.
+   * @type {string}
+   */
+  nickname
+
+  /**
+   * The version of this schema.
+   * @type {string}
+   */
+  version
+
+  /**
+   * The library name of this schema.
+   * @type {string}
+   */
+  library
+
+  /**
+   * The local path for this schema.
+   * @type {string}
+   */
+  localPath
+
+  /**
+   * Constructor.
+   *
+   * @param {string} nickname The nickname of this schema.
+   * @param {string} version The version of this schema.
+   * @param {string?} library The library name of this schema.
+   * @param {string?} localPath The local path for this schema.
+   */
+  constructor(nickname, version, library = '', localPath = '') {
+    this.nickname = nickname
+    this.version = version
+    this.library = library
+    this.localPath = localPath
+  }
+
+  /**
+   * Compute the name for the bundled copy of this schema.
+   *
+   * @returns {string}
+   */
+  get localName() {
+    if (!this.library) {
+      return 'HED' + this.version
+    } else {
+      return 'HED_' + this.library + '_' + this.version
+    }
+  }
+}
+
+/**
+ * A specification mapping schema nicknames to SchemaSpec objects.
+ */
+export class SchemasSpec {
+  /**
+   * The specification mapping data.
+   * @type {Map<string, SchemaSpec[]>}
+   */
+  data
+
+  /**
+   * Constructor.
+   */
+  constructor() {
+    this.data = new Map()
+  }
+
+  /**
+   * Iterator over the specifications.
+   *
+   * @yields {Iterator} - [string, SchemaSpec[]]
+   */
+  *[Symbol.iterator]() {
+    for (const [key, value] of this.data.entries()) {
+      yield [key, value]
+    }
+  }
+
+  /**
+   * Add a schema to this specification.
+   *
+   * @param {SchemaSpec} schemaSpec A schema specification.
+   * @returns {SchemasSpec| map} This object.
+   */
+  addSchemaSpec(schemaSpec) {
+    if (this.data.has(schemaSpec.nickname)) {
+      this.data.get(schemaSpec.nickname).push(schemaSpec)
+    } else {
+      this.data.set(schemaSpec.nickname, [schemaSpec])
+    }
+    return this
+  }
+}
+
+
+
+
+ + + +
+ + + + + + + diff --git a/docs/html/scripts/linenumber.js b/docs/html/scripts/linenumber.js new file mode 100644 index 00000000..12b3b8f7 --- /dev/null +++ b/docs/html/scripts/linenumber.js @@ -0,0 +1,25 @@ +/*global document */ +;(() => { + const source = document.getElementsByClassName('prettyprint source linenums') + let i = 0 + let lineNumber = 0 + let lineId + let lines + let totalLines + let anchorHash + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1) + lines = source[0].getElementsByTagName('li') + totalLines = lines.length + + for (; i < totalLines; i++) { + lineNumber++ + lineId = `line${lineNumber}` + lines[i].id = lineId + if (lineId === anchorHash) { + lines[i].className += ' selected' + } + } + } +})() diff --git a/docs/html/scripts/prettify/Apache-License-2.0.txt b/docs/html/scripts/prettify/Apache-License-2.0.txt new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/docs/html/scripts/prettify/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/docs/html/scripts/prettify/lang-css.js b/docs/html/scripts/prettify/lang-css.js new file mode 100644 index 00000000..ea74782a --- /dev/null +++ b/docs/html/scripts/prettify/lang-css.js @@ -0,0 +1,23 @@ +PR.registerLangHandler( + PR.createSimpleLexer( + [['pln', /^[\t\n\f\r ]+/, null, ' \t\r\n ']], + [ + ['str', /^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/, null], + ['str', /^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/, null], + ['lang-css-str', /^url\(([^"')]*)\)/i], + ['kwd', /^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i, null], + ['lang-css-kw', /^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i], + ['com', /^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//], + ['com', /^(?:<\!--|--\>)/], + ['lit', /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], + ['lit', /^#[\da-f]{3,6}/i], + ['pln', /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i], + ['pun', /^[^\s\w"']+/], + ], + ), + ['css'], +) +PR.registerLangHandler(PR.createSimpleLexer([], [['kwd', /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]), [ + 'css-kw', +]) +PR.registerLangHandler(PR.createSimpleLexer([], [['str', /^[^"')]+/]]), ['css-str']) diff --git a/docs/html/scripts/prettify/prettify.js b/docs/html/scripts/prettify/prettify.js new file mode 100644 index 00000000..2efe7636 --- /dev/null +++ b/docs/html/scripts/prettify/prettify.js @@ -0,0 +1,588 @@ +var q = null +window.PR_SHOULD_USE_CONTINUATION = !0 +;(function () { + function L(a) { + function m(a) { + var f = a.charCodeAt(0) + if (f !== 92) return f + var b = a.charAt(1) + return (f = r[b]) + ? f + : '0' <= b && b <= '7' + ? parseInt(a.substring(1), 8) + : b === 'u' || b === 'x' + ? parseInt(a.substring(2), 16) + : a.charCodeAt(1) + } + function e(a) { + if (a < 32) return (a < 16 ? '\\x0' : '\\x') + a.toString(16) + a = String.fromCharCode(a) + if (a === '\\' || a === '-' || a === '[' || a === ']') a = '\\' + a + return a + } + function h(a) { + for ( + var f = a + .substring(1, a.length - 1) + .match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g), + a = [], + b = [], + o = f[0] === '^', + c = o ? 1 : 0, + i = f.length; + c < i; + ++c + ) { + var j = f[c] + if (/\\[bdsw]/i.test(j)) a.push(j) + else { + var j = m(j), + d + c + 2 < i && '-' === f[c + 1] ? ((d = m(f[c + 2])), (c += 2)) : (d = j) + b.push([j, d]) + d < 65 || + j > 122 || + (d < 65 || j > 90 || b.push([Math.max(65, j) | 32, Math.min(d, 90) | 32]), + d < 97 || j > 122 || b.push([Math.max(97, j) & -33, Math.min(d, 122) & -33])) + } + } + b.sort(function (a, f) { + return a[0] - f[0] || f[1] - a[1] + }) + f = [] + j = [NaN, NaN] + for (c = 0; c < b.length; ++c) (i = b[c]), i[0] <= j[1] + 1 ? (j[1] = Math.max(j[1], i[1])) : f.push((j = i)) + b = ['['] + o && b.push('^') + b.push.apply(b, a) + for (c = 0; c < f.length; ++c) + (i = f[c]), b.push(e(i[0])), i[1] > i[0] && (i[1] + 1 > i[0] && b.push('-'), b.push(e(i[1]))) + b.push(']') + return b.join('') + } + function y(a) { + for ( + var f = a.source.match( + /\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g, + ), + b = f.length, + d = [], + c = 0, + i = 0; + c < b; + ++c + ) { + var j = f[c] + j === '(' ? ++i : '\\' === j.charAt(0) && (j = +j.substring(1)) && j <= i && (d[j] = -1) + } + for (c = 1; c < d.length; ++c) -1 === d[c] && (d[c] = ++t) + for (i = c = 0; c < b; ++c) + (j = f[c]), + j === '(' + ? (++i, d[i] === void 0 && (f[c] = '(?:')) + : '\\' === j.charAt(0) && (j = +j.substring(1)) && j <= i && (f[c] = '\\' + d[i]) + for (i = c = 0; c < b; ++c) '^' === f[c] && '^' !== f[c + 1] && (f[c] = '') + if (a.ignoreCase && s) + for (c = 0; c < b; ++c) + (j = f[c]), + (a = j.charAt(0)), + j.length >= 2 && a === '[' + ? (f[c] = h(j)) + : a !== '\\' && + (f[c] = j.replace(/[A-Za-z]/g, function (a) { + a = a.charCodeAt(0) + return '[' + String.fromCharCode(a & -33, a | 32) + ']' + })) + return f.join('') + } + for (var t = 0, s = !1, l = !1, p = 0, d = a.length; p < d; ++p) { + var g = a[p] + if (g.ignoreCase) l = !0 + else if (/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi, ''))) { + s = !0 + l = !1 + break + } + } + for (var r = { b: 8, t: 9, n: 10, v: 11, f: 12, r: 13 }, n = [], p = 0, d = a.length; p < d; ++p) { + g = a[p] + if (g.global || g.multiline) throw Error('' + g) + n.push('(?:' + y(g) + ')') + } + return RegExp(n.join('|'), l ? 'gi' : 'g') + } + function M(a) { + function m(a) { + switch (a.nodeType) { + case 1: + if (e.test(a.className)) break + for (var g = a.firstChild; g; g = g.nextSibling) m(g) + g = a.nodeName + if ('BR' === g || 'LI' === g) (h[s] = '\n'), (t[s << 1] = y++), (t[(s++ << 1) | 1] = a) + break + case 3: + case 4: + ;(g = a.nodeValue), + g.length && + ((g = p ? g.replace(/\r\n?/g, '\n') : g.replace(/[\t\n\r ]+/g, ' ')), + (h[s] = g), + (t[s << 1] = y), + (y += g.length), + (t[(s++ << 1) | 1] = a)) + } + } + var e = /(?:^|\s)nocode(?:\s|$)/, + h = [], + y = 0, + t = [], + s = 0, + l + a.currentStyle + ? (l = a.currentStyle.whiteSpace) + : window.getComputedStyle && (l = document.defaultView.getComputedStyle(a, q).getPropertyValue('white-space')) + var p = l && 'pre' === l.substring(0, 3) + m(a) + return { a: h.join('').replace(/\n$/, ''), c: t } + } + function B(a, m, e, h) { + m && ((a = { a: m, d: a }), e(a), h.push.apply(h, a.e)) + } + function x(a, m) { + function e(a) { + for (var l = a.d, p = [l, 'pln'], d = 0, g = a.a.match(y) || [], r = {}, n = 0, z = g.length; n < z; ++n) { + var f = g[n], + b = r[f], + o = void 0, + c + if (typeof b === 'string') c = !1 + else { + var i = h[f.charAt(0)] + if (i) (o = f.match(i[1])), (b = i[0]) + else { + for (c = 0; c < t; ++c) + if (((i = m[c]), (o = f.match(i[1])))) { + b = i[0] + break + } + o || (b = 'pln') + } + if ((c = b.length >= 5 && 'lang-' === b.substring(0, 5)) && !(o && typeof o[1] === 'string')) + (c = !1), (b = 'src') + c || (r[f] = b) + } + i = d + d += f.length + if (c) { + c = o[1] + var j = f.indexOf(c), + k = j + c.length + o[2] && ((k = f.length - o[2].length), (j = k - c.length)) + b = b.substring(5) + B(l + i, f.substring(0, j), e, p) + B(l + i + j, c, C(b, c), p) + B(l + i + k, f.substring(k), e, p) + } else p.push(l + i, b) + } + a.e = p + } + var h = {}, + y + ;(function () { + for (var e = a.concat(m), l = [], p = {}, d = 0, g = e.length; d < g; ++d) { + var r = e[d], + n = r[3] + if (n) for (var k = n.length; --k >= 0; ) h[n.charAt(k)] = r + r = r[1] + n = '' + r + p.hasOwnProperty(n) || (l.push(r), (p[n] = q)) + } + l.push(/[\S\s]/) + y = L(l) + })() + var t = m.length + return e + } + function u(a) { + var m = [], + e = [] + a.tripleQuotedStrings + ? m.push([ + 'str', + /^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/, + q, + '\'"', + ]) + : a.multiLineStrings + ? m.push([ + 'str', + /^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, + q, + '\'"`', + ]) + : m.push(['str', /^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/, q, '"\'']) + a.verbatimStrings && e.push(['str', /^@"(?:[^"]|"")*(?:"|$)/, q]) + var h = a.hashComments + h && + (a.cStyleComments + ? (h > 1 + ? m.push(['com', /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, q, '#']) + : m.push([ + 'com', + /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/, + q, + '#', + ]), + e.push(['str', /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, q])) + : m.push(['com', /^#[^\n\r]*/, q, '#'])) + a.cStyleComments && (e.push(['com', /^\/\/[^\n\r]*/, q]), e.push(['com', /^\/\*[\S\s]*?(?:\*\/|$)/, q])) + a.regexLiterals && + e.push([ + 'lang-regex', + /^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/, + ]) + ;(h = a.types) && e.push(['typ', h]) + a = ('' + a.keywords).replace(/^ | $/g, '') + a.length && e.push(['kwd', RegExp('^(?:' + a.replace(/[\s,]+/g, '|') + ')\\b'), q]) + m.push(['pln', /^\s+/, q, ' \r\n\t\xa0']) + e.push( + ['lit', /^@[$_a-z][\w$@]*/i, q], + ['typ', /^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/, q], + ['pln', /^[$_a-z][\w$@]*/i, q], + ['lit', /^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i, q, '0123456789'], + ['pln', /^\\[\S\s]?/, q], + ['pun', /^.[^\s\w"-$'./@\\`]*/, q], + ) + return x(m, e) + } + function D(a, m) { + function e(a) { + switch (a.nodeType) { + case 1: + if (k.test(a.className)) break + if ('BR' === a.nodeName) h(a), a.parentNode && a.parentNode.removeChild(a) + else for (a = a.firstChild; a; a = a.nextSibling) e(a) + break + case 3: + case 4: + if (p) { + var b = a.nodeValue, + d = b.match(t) + if (d) { + var c = b.substring(0, d.index) + a.nodeValue = c + ;(b = b.substring(d.index + d[0].length)) && a.parentNode.insertBefore(s.createTextNode(b), a.nextSibling) + h(a) + c || a.parentNode.removeChild(a) + } + } + } + } + function h(a) { + function b(a, d) { + var e = d ? a.cloneNode(!1) : a, + f = a.parentNode + if (f) { + var f = b(f, 1), + g = a.nextSibling + f.appendChild(e) + for (var h = g; h; h = g) (g = h.nextSibling), f.appendChild(h) + } + return e + } + for (; !a.nextSibling; ) if (((a = a.parentNode), !a)) return + for (var a = b(a.nextSibling, 0), e; (e = a.parentNode) && e.nodeType === 1; ) a = e + d.push(a) + } + var k = /(?:^|\s)nocode(?:\s|$)/, + t = /\r\n?|\n/, + s = a.ownerDocument, + l + a.currentStyle + ? (l = a.currentStyle.whiteSpace) + : window.getComputedStyle && (l = s.defaultView.getComputedStyle(a, q).getPropertyValue('white-space')) + var p = l && 'pre' === l.substring(0, 3) + for (l = s.createElement('LI'); a.firstChild; ) l.appendChild(a.firstChild) + for (var d = [l], g = 0; g < d.length; ++g) e(d[g]) + m === (m | 0) && d[0].setAttribute('value', m) + var r = s.createElement('OL') + r.className = 'linenums' + for (var n = Math.max(0, (m - 1) | 0) || 0, g = 0, z = d.length; g < z; ++g) + (l = d[g]), + (l.className = 'L' + ((g + n) % 10)), + l.firstChild || l.appendChild(s.createTextNode('\xa0')), + r.appendChild(l) + a.appendChild(r) + } + function k(a, m) { + for (var e = m.length; --e >= 0; ) { + var h = m[e] + A.hasOwnProperty(h) ? window.console && console.warn('cannot override language handler %s', h) : (A[h] = a) + } + } + function C(a, m) { + if (!a || !A.hasOwnProperty(a)) a = /^\s*= o && (h += 2) + e >= c && (a += 2) + } + } catch (w) { + 'console' in window && console.log(w && w.stack ? w.stack : w) + } + } + var v = ['break,continue,do,else,for,if,return,while'], + w = [ + [ + v, + 'auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile', + ], + 'catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof', + ], + F = [ + w, + 'alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where', + ], + G = [ + w, + 'abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient', + ], + H = [ + G, + 'as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var', + ], + w = [w, 'debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN'], + I = [ + v, + 'and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None', + ], + J = [ + v, + 'alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END', + ], + v = [v, 'case,done,elif,esac,eval,fi,function,in,local,set,then,until'], + K = + /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/, + N = /\S/, + O = u({ + keywords: [ + F, + H, + w, + 'caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END' + + I, + J, + v, + ], + hashComments: !0, + cStyleComments: !0, + multiLineStrings: !0, + regexLiterals: !0, + }), + A = {} + k(O, ['default-code']) + k( + x( + [], + [ + ['pln', /^[^]*(?:>|$)/], + ['com', /^<\!--[\S\s]*?(?:--\>|$)/], + ['lang-', /^<\?([\S\s]+?)(?:\?>|$)/], + ['lang-', /^<%([\S\s]+?)(?:%>|$)/], + ['pun', /^(?:<[%?]|[%?]>)/], + ['lang-', /^]*>([\S\s]+?)<\/xmp\b[^>]*>/i], + ['lang-js', /^]*>([\S\s]*?)(<\/script\b[^>]*>)/i], + ['lang-css', /^]*>([\S\s]*?)(<\/style\b[^>]*>)/i], + ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i], + ], + ), + ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl'], + ) + k( + x( + [ + ['pln', /^\s+/, q, ' \t\r\n'], + ['atv', /^(?:"[^"]*"?|'[^']*'?)/, q, '"\''], + ], + [ + ['tag', /^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i], + ['atn', /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], + ['lang-uq.val', /^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/], + ['pun', /^[/<->]+/], + ['lang-js', /^on\w+\s*=\s*"([^"]+)"/i], + ['lang-js', /^on\w+\s*=\s*'([^']+)'/i], + ['lang-js', /^on\w+\s*=\s*([^\s"'>]+)/i], + ['lang-css', /^style\s*=\s*"([^"]+)"/i], + ['lang-css', /^style\s*=\s*'([^']+)'/i], + ['lang-css', /^style\s*=\s*([^\s"'>]+)/i], + ], + ), + ['in.tag'], + ) + k(x([], [['atv', /^[\S\s]+/]]), ['uq.val']) + k(u({ keywords: F, hashComments: !0, cStyleComments: !0, types: K }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']) + k(u({ keywords: 'null,true,false' }), ['json']) + k(u({ keywords: H, hashComments: !0, cStyleComments: !0, verbatimStrings: !0, types: K }), ['cs']) + k(u({ keywords: G, cStyleComments: !0 }), ['java']) + k(u({ keywords: v, hashComments: !0, multiLineStrings: !0 }), ['bsh', 'csh', 'sh']) + k(u({ keywords: I, hashComments: !0, multiLineStrings: !0, tripleQuotedStrings: !0 }), ['cv', 'py']) + k( + u({ + keywords: + 'caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END', + hashComments: !0, + multiLineStrings: !0, + regexLiterals: !0, + }), + ['perl', 'pl', 'pm'], + ) + k(u({ keywords: J, hashComments: !0, multiLineStrings: !0, regexLiterals: !0 }), ['rb']) + k(u({ keywords: w, cStyleComments: !0, regexLiterals: !0 }), ['js']) + k( + u({ + keywords: + 'all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes', + hashComments: 3, + cStyleComments: !0, + multilineStrings: !0, + tripleQuotedStrings: !0, + regexLiterals: !0, + }), + ['coffee'], + ) + k(x([], [['str', /^[\S\s]+/]]), ['regex']) + window.prettyPrintOne = function (a, m, e) { + var h = document.createElement('PRE') + h.innerHTML = a + e && D(h, e) + E({ g: m, i: e, h: h }) + return h.innerHTML + } + window.prettyPrint = function (a) { + function m() { + for (var e = window.PR_SHOULD_USE_CONTINUATION ? l.now() + 250 : Infinity; p < h.length && l.now() < e; p++) { + var n = h[p], + k = n.className + if (k.indexOf('prettyprint') >= 0) { + var k = k.match(g), + f, + b + if ((b = !k)) { + b = n + for (var o = void 0, c = b.firstChild; c; c = c.nextSibling) + var i = c.nodeType, o = i === 1 ? (o ? b : c) : i === 3 ? (N.test(c.nodeValue) ? b : o) : o + b = (f = o === b ? void 0 : o) && 'CODE' === f.tagName + } + b && (k = f.className.match(g)) + k && (k = k[1]) + b = !1 + for (o = n.parentNode; o; o = o.parentNode) + if ( + (o.tagName === 'pre' || o.tagName === 'code' || o.tagName === 'xmp') && + o.className && + o.className.indexOf('prettyprint') >= 0 + ) { + b = !0 + break + } + b || + ((b = (b = n.className.match(/\blinenums\b(?::(\d+))?/)) ? (b[1] && b[1].length ? +b[1] : !0) : !1) && + D(n, b), + (d = { g: k, h: n, i: b }), + E(d)) + } + } + p < h.length ? setTimeout(m, 250) : a && a() + } + for ( + var e = [ + document.getElementsByTagName('pre'), + document.getElementsByTagName('code'), + document.getElementsByTagName('xmp'), + ], + h = [], + k = 0; + k < e.length; + ++k + ) + for (var t = 0, s = e[k].length; t < s; ++t) h.push(e[k][t]) + var e = q, + l = Date + l.now || + (l = { + now: function () { + return +new Date() + }, + }) + var p = 0, + d, + g = /\blang(?:uage)?-([\w.]+)(?!\S)/ + m() + } + window.PR = { + createSimpleLexer: x, + registerLangHandler: k, + sourceDecorator: u, + PR_ATTRIB_NAME: 'atn', + PR_ATTRIB_VALUE: 'atv', + PR_COMMENT: 'com', + PR_DECLARATION: 'dec', + PR_KEYWORD: 'kwd', + PR_LITERAL: 'lit', + PR_NOCODE: 'nocode', + PR_PLAIN: 'pln', + PR_PUNCTUATION: 'pun', + PR_SOURCE: 'src', + PR_STRING: 'str', + PR_TAG: 'tag', + PR_TYPE: 'typ', + } +})() diff --git a/docs/html/styles/jsdoc-default.css b/docs/html/styles/jsdoc-default.css new file mode 100644 index 00000000..a2ac5909 --- /dev/null +++ b/docs/html/styles/jsdoc-default.css @@ -0,0 +1,375 @@ +@font-face { + font-family: 'Open Sans'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Regular-webfont.eot'); + src: + local('Open Sans'), + local('OpenSans'), + url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), + url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); +} + +@font-face { + font-family: 'Open Sans Light'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Light-webfont.eot'); + src: + local('Open Sans Light'), + local('OpenSans Light'), + url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Light-webfont.woff') format('woff'), + url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); +} + +html { + overflow: auto; + background-color: #fff; + font-size: 14px; +} + +body { + font-family: 'Open Sans', sans-serif; + line-height: 1.5; + color: #4d4e53; + background-color: white; +} + +a, +a:visited, +a:active { + color: #0095dd; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +header { + display: block; + padding: 0px 4px; +} + +tt, +code, +kbd, +samp { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.class-description { + font-size: 130%; + line-height: 140%; + margin-bottom: 1em; + margin-top: 1em; +} + +.class-description:empty { + margin: 0; +} + +#main { + float: left; + width: 70%; +} + +article dl { + margin-bottom: 40px; +} + +article img { + max-width: 100%; +} + +section { + display: block; + background-color: #fff; + padding: 12px 24px; + border-bottom: 1px solid #ccc; + margin-right: 30px; +} + +.variation { + display: none; +} + +.signature-attributes { + font-size: 60%; + color: #aaa; + font-style: italic; + font-weight: lighter; +} + +nav { + display: block; + float: right; + margin-top: 28px; + width: 30%; + box-sizing: border-box; + border-left: 1px solid #ccc; + padding-left: 16px; +} + +nav ul { + font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; + font-size: 100%; + line-height: 17px; + padding: 0; + margin: 0; + list-style-type: none; +} + +nav ul a, +nav ul a:visited, +nav ul a:active { + font-family: Consolas, Monaco, 'Andale Mono', monospace; + line-height: 18px; + color: #4d4e53; +} + +nav h3 { + margin-top: 12px; +} + +nav li { + margin-top: 6px; +} + +footer { + display: block; + padding: 6px; + margin-top: 12px; + font-style: italic; + font-size: 90%; +} + +h1, +h2, +h3, +h4 { + font-weight: 200; + margin: 0; +} + +h1 { + font-family: 'Open Sans Light', sans-serif; + font-size: 48px; + letter-spacing: -2px; + margin: 12px 24px 20px; +} + +h2, +h3.subsection-title { + font-size: 30px; + font-weight: 700; + letter-spacing: -1px; + margin-bottom: 12px; +} + +h3 { + font-size: 24px; + letter-spacing: -0.5px; + margin-bottom: 12px; +} + +h4 { + font-size: 18px; + letter-spacing: -0.33px; + margin-bottom: 12px; + color: #4d4e53; +} + +h5, +.container-overview .subsection-title { + font-size: 120%; + font-weight: bold; + letter-spacing: -0.01em; + margin: 8px 0 3px 0; +} + +h6 { + font-size: 100%; + letter-spacing: -0.01em; + margin: 6px 0 3px 0; + font-style: italic; +} + +table { + border-spacing: 0; + border: 0; + border-collapse: collapse; +} + +td, +th { + border: 1px solid #ddd; + margin: 0px; + text-align: left; + vertical-align: top; + padding: 4px 6px; + display: table-cell; +} + +thead tr { + background-color: #ddd; + font-weight: bold; +} + +th { + border-right: 1px solid #aaa; +} +tr > th:last-child { + border-right: 1px solid #ddd; +} + +.ancestors, +.attribs { + color: #999; +} +.ancestors a, +.attribs a { + color: #999 !important; + text-decoration: none; +} + +.clear { + clear: both; +} + +.important { + font-weight: bold; + color: #950b02; +} + +.yes-def { + text-indent: -1000px; +} + +.type-signature { + color: #aaa; +} + +.name, +.signature { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.details { + margin-top: 14px; + border-left: 2px solid #ddd; +} +.details dt { + width: 120px; + float: left; + padding-left: 10px; + padding-top: 6px; +} +.details dd { + margin-left: 70px; +} +.details ul { + margin: 0; +} +.details ul { + list-style-type: none; +} +.details li { + margin-left: 30px; + padding-top: 6px; +} +.details pre.prettyprint { + margin: 0; +} +.details .object-value { + padding-top: 0; +} + +.description { + margin-bottom: 1em; + margin-top: 1em; +} + +.code-caption { + font-style: italic; + font-size: 107%; + margin: 0; +} + +.source { + border: 1px solid #ddd; + width: 80%; + overflow: auto; +} + +.prettyprint.source { + width: inherit; +} + +.source code { + font-size: 100%; + line-height: 18px; + display: block; + padding: 4px 12px; + margin: 0; + background-color: #fff; + color: #4d4e53; +} + +.prettyprint code span.line { + display: inline-block; +} + +.prettyprint.linenums { + padding-left: 70px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.prettyprint.linenums ol { + padding-left: 0; +} + +.prettyprint.linenums li { + border-left: 3px #ddd solid; +} + +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * { + background-color: lightyellow; +} + +.prettyprint.linenums li * { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.params .name, +.props .name, +.name code { + color: #4d4e53; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 100%; +} + +.params td.description > p:first-child, +.props td.description > p:first-child { + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +.disabled { + color: #454545; +} diff --git a/docs/html/styles/prettify-jsdoc.css b/docs/html/styles/prettify-jsdoc.css new file mode 100644 index 00000000..5a2526e3 --- /dev/null +++ b/docs/html/styles/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/docs/html/styles/prettify-tomorrow.css b/docs/html/styles/prettify-tomorrow.css new file mode 100644 index 00000000..3c8d71ee --- /dev/null +++ b/docs/html/styles/prettify-tomorrow.css @@ -0,0 +1,163 @@ +/* Tomorrow Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { + color: #4d4d4c; +} + +@media screen { + /* string content */ + .str { + color: #718c00; + } + + /* a keyword */ + .kwd { + color: #8959a8; + } + + /* a comment */ + .com { + color: #8e908c; + } + + /* a type name */ + .typ { + color: #4271ae; + } + + /* a literal value */ + .lit { + color: #f5871f; + } + + /* punctuation */ + .pun { + color: #4d4d4c; + } + + /* lisp open bracket */ + .opn { + color: #4d4d4c; + } + + /* lisp close bracket */ + .clo { + color: #4d4d4c; + } + + /* a markup tag name */ + .tag { + color: #c82829; + } + + /* a markup attribute name */ + .atn { + color: #f5871f; + } + + /* a markup attribute value */ + .atv { + color: #3e999f; + } + + /* a declaration */ + .dec { + color: #f5871f; + } + + /* a variable name */ + .var { + color: #c82829; + } + + /* a function name */ + .fun { + color: #4271ae; + } +} +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { + color: #060; + } + + .kwd { + color: #006; + font-weight: bold; + } + + .com { + color: #600; + font-style: italic; + } + + .typ { + color: #404; + font-weight: bold; + } + + .lit { + color: #044; + } + + .pun, + .opn, + .clo { + color: #440; + } + + .tag { + color: #006; + font-weight: bold; + } + + .atn { + color: #404; + } + + .atv { + color: #060; + } +} +/* Style */ +/* +pre.prettyprint { + background: white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 12px; + line-height: 1.5; + border: 1px solid #ccc; + padding: 10px; } +*/ + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ +} + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ +} diff --git a/docs/html/utils_array.js.html b/docs/html/utils_array.js.html new file mode 100644 index 00000000..03ae7c65 --- /dev/null +++ b/docs/html/utils_array.js.html @@ -0,0 +1,204 @@ + + + + + JSDoc: Source: utils/array.js + + + + + + + + + +
+

Source: utils/array.js

+ +
+
+
/**
+ * Get number of instances of an element in an array.
+ *
+ * @param {Array} array The array to search.
+ * @param {*} elementToCount The element to search for.
+ * @returns {number} The number of instances of the element in the array.
+ */
+export const getElementCount = function (array, elementToCount) {
+  let count = 0
+  for (let i = 0; i < array.length; i++) {
+    if (array[i] === elementToCount) {
+      count++
+    }
+  }
+  return count
+}
+
+/**
+ * Apply a function recursively to an array.
+ *
+ * @template T,U
+ * @param {function(T): U} fn The function to apply.
+ * @param {T[]} array The array to map.
+ * @returns {U[]} The mapped array.
+ */
+export function recursiveMap(fn, array) {
+  if (Array.isArray(array)) {
+    return array.map((element) => recursiveMap(fn, element))
+  } else {
+    return fn(array)
+  }
+}
+
+
+
+
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Sat Feb 08 2025 11:13:20 + GMT-0600 (Central Standard Time) +
+ + + + + diff --git a/docs/html/utils_files.js.html b/docs/html/utils_files.js.html new file mode 100644 index 00000000..051bd4a0 --- /dev/null +++ b/docs/html/utils_files.js.html @@ -0,0 +1,207 @@ + + + + + JSDoc: Source: utils/files.js + + + + + + + + + +
+

Source: utils/files.js

+ +
+
+
import fs from 'fs'
+
+import fetch from 'cross-fetch'
+
+/**
+ * Read a local file.
+ *
+ * @param {string} fileName - The file path.
+ * @returns {Promise} - A promise with the file contents.
+ */
+export function readFile(fileName) {
+  return new Promise((resolve, reject) => {
+    fs.readFile(fileName, 'utf8', (err, data) => {
+      if (err) {
+        reject(err)
+      } else {
+        resolve(data)
+      }
+    })
+  })
+}
+
+/**
+ * Read a remote file using HTTPS.
+ *
+ * @param {string} url The remote URL.
+ * @returns {Promise<string>} A promise with the file contents.
+ */
+export async function readHTTPSFile(url) {
+  const response = await fetch(url)
+  if (!response.ok) {
+    throw new Error(`Server responded to ${url} with status code ${response.status}: ${response.statusText}`)
+  }
+  return response.text()
+}
+
+
+
+
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Sat Feb 08 2025 11:13:20 + GMT-0600 (Central Standard Time) +
+ + + + + diff --git a/docs/html/utils_hedData.js.html b/docs/html/utils_hedData.js.html new file mode 100644 index 00000000..223b10ce --- /dev/null +++ b/docs/html/utils_hedData.js.html @@ -0,0 +1,189 @@ + + + + + JSDoc: Source: utils/hedData.js + + + + + + + + + +
+

Source: utils/hedData.js

+ +
+
+
import lt from 'semver/functions/lt'
+
+/**
+ * Determine the HED generation for a base schema version number.
+ *
+ * @param {string} version A HED base schema version number.
+ * @returns {number} The HED generation the base schema belongs to.
+ */
+export const getGenerationForSchemaVersion = function (version) {
+  if (lt(version, '4.0.0')) {
+    return 1
+  } else if (lt(version, '8.0.0-alpha')) {
+    return 2
+  } else {
+    return 3
+  }
+}
+
+
+
+
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Sat Feb 08 2025 11:13:20 + GMT-0600 (Central Standard Time) +
+ + + + + diff --git a/docs/html/utils_hedStrings.js.html b/docs/html/utils_hedStrings.js.html new file mode 100644 index 00000000..14a1d5bb --- /dev/null +++ b/docs/html/utils_hedStrings.js.html @@ -0,0 +1,248 @@ + + + + + JSDoc: Source: utils/hedStrings.js + + + + + + + + + +
+

Source: utils/hedStrings.js

+ +
+
+
import pluralize from 'pluralize'
+pluralize.addUncountableRule('hertz')
+
+/**
+ * Replace the end of a HED tag with a pound sign.
+ */
+export const replaceTagNameWithPound = function (formattedTag) {
+  const lastTagSlashIndex = formattedTag.lastIndexOf('/')
+  if (lastTagSlashIndex !== -1) {
+    return formattedTag.substring(0, lastTagSlashIndex) + '/#'
+  } else {
+    return '#'
+  }
+}
+
+/**
+ * Get the indices of all slashes in a HED tag.
+ */
+export const getTagSlashIndices = function (tag) {
+  const indices = []
+  let i = -1
+  while ((i = tag.indexOf('/', i + 1)) >= 0) {
+    indices.push(i)
+  }
+  return indices
+}
+
+/**
+ * Get the last part of a HED tag.
+ *
+ * @param {string} tag A HED tag
+ * @param {string} character The character to use as a separator.
+ * @returns {string} The last part of the tag using the given separator.
+ */
+export const getTagName = function (tag, character = '/') {
+  const lastSlashIndex = tag.lastIndexOf(character)
+  if (lastSlashIndex === -1) {
+    return tag
+  } else {
+    return tag.substring(lastSlashIndex + 1)
+  }
+}
+
+/**
+ * Get the HED tag prefix (up to the last slash).
+ */
+export const getParentTag = function (tag, character = '/') {
+  const lastSlashIndex = tag.lastIndexOf(character)
+  if (lastSlashIndex === -1) {
+    return tag
+  } else {
+    return tag.substring(0, lastSlashIndex)
+  }
+}
+
+const openingGroupCharacter = '('
+const closingGroupCharacter = ')'
+
+/**
+ * Determine whether a HED string is a group (surrounded by parentheses).
+ *
+ * @param {string} hedString A HED string.
+ */
+export const hedStringIsAGroup = function (hedString) {
+  const trimmedHedString = hedString.trim()
+  return trimmedHedString.startsWith(openingGroupCharacter) && trimmedHedString.endsWith(closingGroupCharacter)
+}
+
+/**
+ * Return a copy of a group tag with the surrounding parentheses removed.
+ *
+ * @param {string} tagGroup A tag group string.
+ */
+export const removeGroupParentheses = function (tagGroup) {
+  return tagGroup.slice(1, -1)
+}
+
+
+
+
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Sat Feb 08 2025 11:13:20 + GMT-0600 (Central Standard Time) +
+ + + + + diff --git a/docs/html/utils_memoizer.js.html b/docs/html/utils_memoizer.js.html new file mode 100644 index 00000000..e5576a68 --- /dev/null +++ b/docs/html/utils_memoizer.js.html @@ -0,0 +1,218 @@ + + + + + JSDoc: Source: utils/memoizer.js + + + + + + + + + +
+

Source: utils/memoizer.js

+ +
+
+
/** Utility classes. **/
+
+import { IssueError } from '../issues/issues'
+
+/**
+ * Superclass for property memoization until we can get away with private fields.
+ */
+export default class Memoizer {
+  /**
+   * Map containing memoized properties (string --> any).
+   *
+   * @type {Map}
+   * @private
+   */
+  _memoizedProperties
+
+  /**
+   * Constructor.
+   */
+  constructor() {
+    this._memoizedProperties = new Map()
+  }
+
+  /**
+   * Memoize a property.
+   *
+   * @template T
+   * @param {string} propertyName The property name.
+   * @param {function() : T} valueComputer A function to compute the property's value.
+   * @returns {T} The computed value.
+   * @protected
+   */
+  _memoize(propertyName, valueComputer) {
+    if (!propertyName) {
+      IssueError.generateAndThrow('internalConsistencyError', {
+        message: 'Invalid property name in Memoizer subclass.',
+      })
+    }
+    if (this._memoizedProperties.has(propertyName)) {
+      return this._memoizedProperties.get(propertyName)
+    }
+    const value = valueComputer()
+    this._memoizedProperties.set(propertyName, value)
+    return value
+  }
+}
+
+
+
+
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Sat Feb 08 2025 11:13:20 + GMT-0600 (Central Standard Time) +
+ + + + + diff --git a/docs/html/utils_string.js.html b/docs/html/utils_string.js.html new file mode 100644 index 00000000..2fecff1f --- /dev/null +++ b/docs/html/utils_string.js.html @@ -0,0 +1,258 @@ + + + + + JSDoc: Source: utils/string.js + + + + + + + + + +
+

Source: utils/string.js

+ +
+
+
import date from 'date-and-time'
+import { parseISO, isValid as dateIsValid } from 'date-fns'
+const rfc3339ish = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(.\d+)?$/
+const digitExpression = /^-?\d+(?:\.\d+)?(?:[Ee]-?\d+)?$/
+
+/**
+ * Check if a string is empty or only whitespace.
+ *
+ * @param {string} string The string to check.
+ * @returns {boolean} Whether the string is empty.
+ */
+export const stringIsEmpty = function (string) {
+  return !string.trim()
+}
+
+/**
+ * Get number of instances of an character in a string.
+ *
+ * @param {string} string The string to search.
+ * @param {string} characterToCount The character to search for.
+ * @returns {number} The number of instances of the character in the string.
+ */
+export const getCharacterCount = function (string, characterToCount) {
+  return string.split(characterToCount).length - 1
+}
+
+/**
+ * Get a copy of a string with the first letter capitalized.
+ *
+ * @param {string} string The string to capitalize.
+ * @returns {string} The capitalized string.
+ */
+export const capitalizeString = function (string) {
+  return string.charAt(0).toUpperCase() + string.substring(1)
+}
+
+/**
+ * Determine if a string is a valid clock face time.
+ *
+ * @param {string} timeString The string to check.
+ * @returns {boolean} Whether the string is a valid clock face time.
+ */
+export const isClockFaceTime = function (timeString) {
+  return date.isValid(timeString, 'HH:mm') || date.isValid(timeString, 'HH:mm:ss')
+}
+
+/**
+ * Determine if a string is a valid date-time.
+ *
+ * @param {string} dateTimeString The string to check.
+ * @returns {boolean} Whether the string is a valid date-time.
+ */
+export const isDateTime = function (dateTimeString) {
+  return dateIsValid(parseISO(dateTimeString)) && rfc3339ish.test(dateTimeString)
+}
+
+/**
+ * Determine if a string is a valid number.
+ *
+ * @param {string} numericString The string to check.
+ * @returns {boolean} Whether the string is a valid number.
+ */
+export const isNumber = function (numericString) {
+  return digitExpression.test(numericString)
+}
+
+/**
+ * Parse a template literal string.
+ *
+ * Copied from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals.
+ *
+ * @param {string[]} strings The literal parts of the template string.
+ * @param {(number|string)} keys The keys of the closure arguments.
+ * @returns {function(...[*]): string} A closure to fill the string template.
+ */
+export const stringTemplate = function (strings, ...keys) {
+  return function (...values) {
+    const dict = values[values.length - 1] ?? {}
+    const result = [strings[0]]
+    keys.forEach((key, i) => {
+      const value = Number.isInteger(key) ? values[key] : dict[key]
+      result.push(value, strings[i + 1])
+    })
+    return result.join('')
+  }
+}
+
+
+
+
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Sat Feb 08 2025 11:13:20 + GMT-0600 (Central Standard Time) +
+ + + + + diff --git a/docs/html/utils_xml2js.js.html b/docs/html/utils_xml2js.js.html new file mode 100644 index 00000000..2db6a6bd --- /dev/null +++ b/docs/html/utils_xml2js.js.html @@ -0,0 +1,204 @@ + + + + + JSDoc: Source: utils/xml2js.js + + + + + + + + + +
+

Source: utils/xml2js.js

+ +
+
+
/**
+ * Recursively set a field on each node of the tree pointing to the node's parent.
+ *
+ * @param {object} node The child node.
+ * @param {object} parent The parent node.
+ */
+const setNodeParent = function (node, parent) {
+  // Assume that we've already run this function if so.
+  if ('$parent' in node) {
+    return
+  }
+  node.$parent = parent
+  const childNodes = node.node ?? []
+  for (const child of childNodes) {
+    setNodeParent(child, node)
+  }
+}
+
+/**
+ * Handle top level of parent-setting recursion before passing to setNodeParent.
+ *
+ * @param {object} node The child node.
+ * @param {object} parent The parent node.
+ */
+export const setParent = function (node, parent) {
+  if (node.schema) {
+    node.$parent = null
+    setNodeParent(node.schema[0], null)
+  } else {
+    setNodeParent(node, parent)
+  }
+}
+
+
+
+
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Sat Feb 08 2025 11:13:20 + GMT-0600 (Central Standard Time) +
+ + + + + diff --git a/docs/html/utils_xpath.js.html b/docs/html/utils_xpath.js.html new file mode 100644 index 00000000..3401fdc2 --- /dev/null +++ b/docs/html/utils_xpath.js.html @@ -0,0 +1,253 @@ + + + + + JSDoc: Source: utils/xpath.js + + + + + + + + + +
+

Source: utils/xpath.js

+ +
+
+
// Temporary XPath implementation until the xml2js-xpath package adds needed functionality.
+
+const childToParent = {
+  unitClassDefinition: 'unitClassDefinitions',
+  unitModifierDefinition: 'unitModifierDefinitions',
+  valueClassDefinition: 'valueClassDefinitions',
+  schemaAttributeDefinition: 'schemaAttributeDefinitions',
+  propertyDefinition: 'propertyDefinitions',
+}
+
+/**
+ * Execute an XPath query on an xml2js object.
+ *
+ * @param {object} element An xml2js element.
+ * @param {string} query An XPath query.
+ * @returns {object[]} An array of xml2js elements matching the query.
+ */
+export const find = function (element, query) {
+  const { elementName, attributeName } = parseXPath(query)
+
+  if (elementName === 'node') {
+    const parentElement = element.schema?.[0] ?? element
+    const nodeList = parentElement.node ?? []
+    return nodeList.flatMap((child) => search(child, elementName, attributeName))
+  }
+
+  return element?.[childToParent[elementName]]?.[0][elementName] ?? []
+}
+
+/**
+ * Parse an XPath query.
+ *
+ * This is a minimal parser only suitable for this package.
+ *
+ * @param {string} query An XPath query.
+ * @returns {object} The parsed search parameters.
+ */
+const parseXPath = function (query) {
+  const nodeQuery = /^\/\/(\w+)$/
+  const attributeQuery = /^\/\/(\w+)\[@(\w+)]$/
+
+  let elementName, attributeName
+
+  const attributeMatch = query.match(attributeQuery)
+  if (attributeMatch) {
+    ;[, elementName, attributeName] = attributeMatch
+  } else {
+    const nodeMatch = query.match(nodeQuery)
+    if (nodeMatch) {
+      ;[, elementName] = nodeMatch
+    } else {
+      return {}
+    }
+  }
+  return { elementName: elementName, attributeName: attributeName }
+}
+
+/**
+ * Search for children of an element with a given name and attribute.
+ *
+ * @param {object} element An xml2js element.
+ * @param {string} elementName The element name.
+ * @param {string} attributeName The attribute name.
+ * @returns {object[]} An array of xml2js elements with the given name and attribute.
+ */
+const search = function (element, elementName, attributeName) {
+  let result = []
+  if (attributeName === undefined || ('$' in element && attributeName in element.$)) {
+    result.push(element)
+  }
+  if (elementName in element) {
+    result = result.concat(
+      element[elementName].flatMap((element) => {
+        return search(element, elementName, attributeName)
+      }),
+    )
+  }
+  return result
+}
+
+
+
+
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Sat Feb 08 2025 11:13:20 + GMT-0600 (Central Standard Time) +
+ + + + + diff --git a/jsdoc.conf.json b/jsdoc.conf.json index 4b664f48..f9130b68 100644 --- a/jsdoc.conf.json +++ b/jsdoc.conf.json @@ -8,7 +8,7 @@ "excludePattern": "(node_modules/|docs/|src/data/|spec_tests/|tests/)" }, "opts": { - "destination": "docs/_build/html/jsdoc", + "destination": "docs/html", "recurse": true } } diff --git a/spec_tests/javascriptTests.json b/spec_tests/javascriptTests.json index 473cb2ea..7ed47a4d 100644 --- a/spec_tests/javascriptTests.json +++ b/spec_tests/javascriptTests.json @@ -2874,6 +2874,14 @@ "HED": "(Item-count/#, {response_time})" } }, + { + "event_code": { + "HED": { + "face": "{HED}", + "ball": "Red" + } + } + }, { "event_code": { "HED": { @@ -2937,6 +2945,21 @@ [5.2, 0, "n/a", "face", ""], [5.5, 0, "7,3", "face", "n/a"] ] + }, + { + "sidecar": { + "event_code": { + "HED": { + "face": "{HED}", + "ball": "Red" + } + } + }, + "events": [ + ["onset", "duration", "response_time", "event_code"], + [4.5, 0, 3.4, "face"], + [5.0, 0, 6.8, "ball"] + ] } ] } @@ -3287,6 +3310,74 @@ } } }, + { + "error_code": "SIDECAR_KEY_MISSING", + "alt_codes": [], + "name": "sidecar-refers-to-missing-tsv-hed-column", + "description": "(Warning) A sidecar uses a {HED} column which does not appear in the corresponding tsv file.", + "warning": true, + "schema": "8.3.0", + "definitions": ["(Definition/Acc/#, (Acceleration/# m-per-s^2, Red))", "(Definition/MyColor, (Label/Pie))"], + "tests": { + "string_tests": { + "fails": [], + "passes": [] + }, + "sidecar_tests": { + "fails": [], + "passes": [ + { + "event_code": { + "HED": { + "face": "{HED}", + "ball": "Red" + } + } + } + ] + }, + "event_tests": { + "fails": [], + "passes": [] + }, + "combo_tests": { + "fails": [ + { + "sidecar": { + "event_code": { + "HED": { + "face": "{HED}", + "ball": "Red" + } + } + }, + "events": [ + ["onset", "duration", "event_code"], + [4.5, 0, "face"], + [5.0, 0, "ball"] + ] + } + ], + "passes": [ + { + "sidecar": { + "event_code": { + "HED": { + "face": "{HED}", + "ball": "Red" + } + } + }, + "events": [ + ["onset", "duration", "event_code", "HED"], + [4.5, 0, "face", "Green"], + [5.0, 0, "ball", "Black"] + ] + } + ] + } + } + }, { "error_code": "STYLE_WARNING", "alt_codes": [], diff --git a/src/bids/index.js b/src/bids/index.js index 98ce636b..992df04b 100644 --- a/src/bids/index.js +++ b/src/bids/index.js @@ -1,5 +1,4 @@ import { buildBidsSchemas } from './schema' -import validateBidsDataset from './validate' import { BidsJsonFile, BidsSidecar } from './types/json' import { BidsTsvFile } from './types/tsv' import { BidsHedIssue, BidsIssue } from './types/issues' @@ -15,7 +14,6 @@ export { BidsHedSidecarValidator, BidsHedTsvValidator, buildBidsSchemas, - validateBidsDataset, } export default { @@ -27,5 +25,4 @@ export default { BidsHedSidecarValidator, BidsHedTsvValidator, buildBidsSchemas, - validateBidsDataset, } diff --git a/src/bids/types/dataset.js b/src/bids/types/dataset.js deleted file mode 100644 index c1dc7cb9..00000000 --- a/src/bids/types/dataset.js +++ /dev/null @@ -1,36 +0,0 @@ -export class BidsDataset { - /** - * The dataset's event file data. - * @type {BidsTsvFile[]} - */ - eventData - /** - * The dataset's bidsFile data. - * @type {BidsSidecar[]} - */ - sidecarData - /** - * The dataset's dataset_description.json file. - * @type {BidsJsonFile} - */ - datasetDescription - /** - * The dataset's root directory as an absolute path. - * @type {string|null} - */ - datasetRootDirectory - - constructor(eventData, sidecarData, datasetDescription, datasetRootDirectory = null) { - this.eventData = eventData - this.sidecarData = sidecarData - this.datasetDescription = datasetDescription - this.datasetRootDirectory = datasetRootDirectory - } - - get hasHedData() { - return ( - this.sidecarData.some((sidecarFileData) => sidecarFileData.hasHedData()) || - this.eventData.some((tsvFileData) => tsvFileData.hasHedData()) - ) - } -} diff --git a/src/bids/types/basic.js b/src/bids/types/file.js similarity index 100% rename from src/bids/types/basic.js rename to src/bids/types/file.js diff --git a/src/bids/types/json.js b/src/bids/types/json.js index 253802aa..7753fdbe 100644 --- a/src/bids/types/json.js +++ b/src/bids/types/json.js @@ -3,7 +3,7 @@ import isPlainObject from 'lodash/isPlainObject' import { sidecarValueHasHed } from '../utils' import { parseHedString } from '../../parser/parser' import ParsedHedString from '../../parser/parsedHedString' -import { BidsFile } from './basic' +import { BidsFile } from './file' import BidsHedSidecarValidator from '../validator/sidecarValidator' import { IssueError } from '../../issues/issues' import { DefinitionManager, Definition } from '../../parser/definitionManager' diff --git a/src/bids/types/tsv.js b/src/bids/types/tsv.js index 1e1597b8..b0e18d14 100644 --- a/src/bids/types/tsv.js +++ b/src/bids/types/tsv.js @@ -1,6 +1,6 @@ import isPlainObject from 'lodash/isPlainObject' -import { BidsFile } from './basic' +import { BidsFile } from './file' import { convertParsedTSVData, parseTSV } from '../tsvParser' import { BidsSidecar } from './json' import BidsHedTsvValidator from '../validator/tsvValidator' diff --git a/src/bids/validate.js b/src/bids/validate.js deleted file mode 100644 index 68e2ea75..00000000 --- a/src/bids/validate.js +++ /dev/null @@ -1,135 +0,0 @@ -import { buildBidsSchemas } from './schema' -import { BidsHedIssue, BidsIssue } from './types/issues' -import { generateIssue } from '../issues/issues' - -/** - * Validate a BIDS dataset. - * - * @param {BidsDataset} dataset The BIDS dataset. - * @param {SchemasSpec} schemaDefinition The version spec for the schema to be loaded. - * @returns {Promise} A promise for list of Any issues found. - */ -export async function validateBidsDataset(dataset, schemaDefinition) { - const validator = new BidsHedValidator(dataset, schemaDefinition) - return validator.validate() -} - -export default validateBidsDataset - -/** - * A validator for HED content in a BIDS dataset. - */ -class BidsHedValidator { - /** - * The BIDS dataset being validated. - * @type {BidsDataset} - */ - dataset - /** - * The schema specification override. - * @type {SchemasSpec} - */ - schemaDefinition - /** - * The HED schema collection being validated against. - * @type {Schemas} - */ - hedSchemas - /** - * The issues found during validation. - * @type {BidsIssue[]} - */ - issues - - /** - * Constructor. - * - * @param {BidsDataset} dataset The BIDS dataset being validated. - * @param {SchemasSpec} schemaDefinition The version spec for the schema to be loaded. - */ - constructor(dataset, schemaDefinition) { - this.dataset = dataset - this.schemaDefinition = schemaDefinition - this.issues = [] - } - - async validate() { - this.issues.push(...(await this._buildSchemas())) - if (this.issues.length > 0) { - return this.issues - } - try { - this.validateFullDataset() - } catch (internalError) { - return BidsIssue.generateInternalErrorPromise(internalError, this.dataset.datasetDescription.file) - } - return this.issues - } - - async _buildSchemas() { - try { - this.hedSchemas = await buildBidsSchemas(this.dataset.datasetDescription, this.schemaDefinition) - if (this.hedSchemas === null && this.dataset.hasHedData) { - return [ - BidsHedIssue.fromHedIssue( - generateIssue('missingSchemaSpecification', {}), - this.dataset.datasetDescription.file, - ), - ] - } - return [] - } catch (schemaIssues) { - return BidsHedIssue.fromHedIssues(schemaIssues, this.dataset.datasetDescription.file) - } - } - - /** - * Validate a full BIDS dataset using a HED schema collection. - * - * @returns {BidsIssue[]} Any issues found. - */ - validateFullDataset() { - this._validateFiles(this.dataset.sidecarData) - if (BidsIssue.anyAreErrors(this.issues)) { - return this.issues - } - this._validateFiles(this.dataset.eventData) - return this.issues - } - - /** - * Validate a set of BIDS files using a HED schema collection. - * - * @param {BidsFile[]} files The list of files. - * @private - */ - _validateFiles(files) { - for (const file of files) { - const schemaFound = this._validateFile(file) - if (!schemaFound) { - return - } - } - } - - /** - * Validate a BIDS file using a HED schema collection. - * - * @returns {boolean} If the schema was found by the validator. - * @private - */ - _validateFile(file) { - const issues = file.validate(this.hedSchemas) - if (issues === null) { - this.issues.push( - BidsHedIssue.fromHedIssue( - generateIssue('missingSchemaSpecification', {}), - this.dataset.datasetDescription.file, - ), - ) - return false - } - this.issues.push(...issues) - return true - } -} diff --git a/src/bids/validator/validator.js b/src/bids/validator/validator.js index 559c843f..fcd77332 100644 --- a/src/bids/validator/validator.js +++ b/src/bids/validator/validator.js @@ -1,5 +1,3 @@ -import { BidsIssue } from '../types/issues' - /** * Validator base class for HED data in BIDS TSV files. */ diff --git a/src/schema/init.js b/src/schema/init.js index 392a1184..d45b56e0 100644 --- a/src/schema/init.js +++ b/src/schema/init.js @@ -1,25 +1,12 @@ import zip from 'lodash/zip' -import semver from 'semver' -import { SchemasSpec } from './specs' import loadSchema from './loader' import { setParent } from '../utils/xml2js' import SchemaParser from './parser' import PartneredSchemaMerger from './schemaMerger' -import { IssueError } from '../issues/issues' import { Schema, Schemas } from './containers' -/** - * Determine whether a HED schema is based on the HED 3 spec. - * - * @param {object} xmlData HED XML data. - * @returns {boolean} Whether the schema is a HED 3 schema. - */ -const isHed3Schema = function (xmlData) { - return xmlData.HED.$.library !== undefined || semver.gte(xmlData.HED.$.version, '8.0.0-alpha.3') -} - /** * Build a single schema container object from an XML file. * @@ -27,9 +14,6 @@ const isHed3Schema = function (xmlData) { * @returns {Schema} The HED schema object. */ const buildSchemaObject = function (xmlData) { - if (!isHed3Schema(xmlData)) { - IssueError.generateAndThrow('deprecatedStandardSchemaVersion', { version: xmlData.HED.$.version }) - } const rootElement = xmlData.HED setParent(rootElement, null) const schemaEntries = new SchemaParser(rootElement).parse()