Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion spec_tests/jsonTests.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ describe('HED validation using JSON tests', () => {
try {
const defManager = new DefinitionManager()
defManager.addDefinitions(defList)
const bidsSide = new BidsSidecar(`sidecar`, { relativePath: 'bidsFile test' }, JSON.parse(side), defManager)
const bidsSide = new BidsSidecar(`sidecar`, { relativePath: 'sidecar test' }, JSON.parse(side), defManager)
issues = bidsSide.validate(hedSchema)
} catch (e) {
issues = [convertIssue(e)]
Expand Down
19 changes: 5 additions & 14 deletions src/bids/types/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ export class BidsFile {
* This is used to generate {@link BidsHedIssue} objects.
* @type {Object}
*/

file

/**
* The validator class used to validate this file.
* @private
*/
_validatorClass
#validatorClass

/**
* Constructor.
*
* @param {string} name - The name of the file -- used for messages.
* @param {Object} file - The representation of the file for error messages.
Expand All @@ -33,19 +34,9 @@ export class BidsFile {
constructor(name, file, validatorClass) {
this.name = name
this.file = file
this._validatorClass = validatorClass
this.#validatorClass = validatorClass
}

// /**
// * Parse this bidsFile's HED strings within the bidsFile structure.
// *
// * @param {Schemas} hedSchemas - The HED schema collection.
// * @returns {Array} [Issue[], Issue[]] Any errors and warnings found
// */
// parseHed(hedSchemas) {
// return [[], []]
// }

/**
* Whether this is a TSV file timeline file.
*
Expand Down Expand Up @@ -101,6 +92,6 @@ export class BidsFile {
* @returns {function} (typeof BidsValidator) A subclass constructor of {@link BidsValidator}.
*/
get validatorClass() {
return this._validatorClass
return this.#validatorClass
}
}
7 changes: 7 additions & 0 deletions src/bids/types/issues.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,43 @@ export class BidsHedIssue {
* @type {Object}
*/
file

/**
* The HED Issue object corresponding to this object.
* @type {Issue}
*/
hedIssue

/**
* The BIDS issue code.
* @type {string}
*/
code

/**
* The HED spec code for this issue.
* @type {string}
*/
subCode

/**
* The severity of this issue.
* @type {string}
*/
severity

/**
* The issue message for this issue.
* @type {string}
*/
issueMessage

/**
* The line at which the issue was found.
* @type {number}
*/
line

/**
* The location of the file at which the issue was found.
* @type {string}
Expand Down
85 changes: 48 additions & 37 deletions src/bids/types/json.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import isPlainObject from 'lodash/isPlainObject'

import { sidecarValueHasHed } from '../utils'
import { parseHedString } from '../../parser/parser'
import ParsedHedString from '../../parser/parsedHedString'
import { BidsFile } from './file'
Expand All @@ -21,6 +20,7 @@ export class BidsJsonFile extends BidsFile {
jsonData

/**
* Constructor.
*
* @param {string} name - The name of the JSON file.
* @param {Object} file - The object representing this file.
Expand All @@ -34,19 +34,19 @@ export class BidsJsonFile extends BidsFile {

export class BidsSidecar extends BidsJsonFile {
/**
* The extracted keys for this bidsFile (string --> BidsSidecarKey)
* The extracted keys for this sidecar (string --> BidsSidecarKey)
* @type {Map}
*/
sidecarKeys

/**
* The extracted HED data for this bidsFile (string --> string | Object: string, string
* The extracted HED data for this sidecar (string --> string | Object: string, string
* @type {Map}
*/
hedData

/**
* The parsed HED data for this bidsFile (string --> ParsedHedString | Map: string --> ParsedHedString).
* The parsed HED data for this sidecar (string --> ParsedHedString | Map: string --> ParsedHedString).
* @type {Map}
*/
parsedHedData
Expand Down Expand Up @@ -84,7 +84,7 @@ export class BidsSidecar extends BidsJsonFile {
/**
* Constructor.
*
* @param {string} name The name of the bidsFile file.
* @param {string} name The name of the sidecar file.
* @param {Object} file The file object representing this file.
* @param {Object} sidecarData The raw JSON data.
* @param {DefinitionManager } defManager - The external definitions to use
Expand All @@ -93,12 +93,12 @@ export class BidsSidecar extends BidsJsonFile {
super(name, file, sidecarData)
this.columnSpliceMapping = new Map()
this.columnSpliceReferences = new Set()
this._setDefinitions(defManager)
this._filterHedStrings()
this._categorizeHedStrings()
this.#setDefinitions(defManager)
this.#filterHedStrings()
this.#categorizeHedStrings()
}

_setDefinitions(defManager) {
#setDefinitions(defManager) {
if (defManager instanceof DefinitionManager) {
this.definitions = defManager
} else if (!defManager) {
Expand All @@ -111,10 +111,10 @@ export class BidsSidecar extends BidsJsonFile {
}

/**
* Create the bidsFile key map from the JSON.
* Create the sidecar key map from the JSON.
* @private
*/
_filterHedStrings() {
#filterHedStrings() {
this.sidecarKeys = new Map(
Object.entries(this.jsonData)
.map(([key, value]) => {
Expand All @@ -125,17 +125,28 @@ export class BidsSidecar extends BidsJsonFile {
IssueError.generateAndThrow('illegalSidecarHedKey')
}

if (sidecarValueHasHed(value)) {
if (BidsSidecar.#sidecarValueHasHed(value)) {
return [trimmedKey, new BidsSidecarKey(trimmedKey, value.HED, this)]
}

this._verifyKeyHasNoDeepHed(key, value)
BidsSidecar.#verifyKeyHasNoDeepHed(key, value)
return null
})
.filter(Boolean),
)
}

/**
* Determine whether a sidecar value has HED data.
*
* @param {Object} sidecarValue A BIDS sidecar value.
* @returns {boolean} Whether the sidecar value has HED data.
* @private
*/
static #sidecarValueHasHed(sidecarValue) {
return sidecarValue !== null && typeof sidecarValue === 'object' && sidecarValue.HED !== undefined
}

/**
* Verify that a column has no deeply nested "HED" keys.
*
Expand All @@ -144,23 +155,23 @@ export class BidsSidecar extends BidsJsonFile {
* @throws {IssueError} If an invalid "HED" key is found.
* @private
*/
_verifyKeyHasNoDeepHed(key, value) {
static #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)
BidsSidecar.#verifyKeyHasNoDeepHed(subkey, subvalue)
}
}

/**
* Categorize the column strings into value strings and categorical strings
* @private
*/
_categorizeHedStrings() {
#categorizeHedStrings() {
this.hedValueStrings = []
this.hedCategoricalStrings = []
this.hedData = new Map()
Expand All @@ -185,7 +196,7 @@ export class BidsSidecar extends BidsJsonFile {
}

/**
* Parse this bidsFile's HED strings within the bidsFile structure.
* Parse this sidecar's HED strings within the sidecar structure.
*
* The parsed strings are placed into {@link parsedHedData}.
*
Expand All @@ -206,42 +217,42 @@ export class BidsSidecar extends BidsJsonFile {
this.parsedHedData.set(name, sidecarKey.parsedCategoryMap)
}
}
this._generateSidecarColumnSpliceMap()
this.#generateSidecarColumnSpliceMap()
return [errors, warnings]
}

/**
* Generate a mapping of an individual BIDS bidsFile's curly brace references.
* Generate a mapping of an individual BIDS sidecar's curly brace references.
*
* @private
*/
_generateSidecarColumnSpliceMap() {
#generateSidecarColumnSpliceMap() {
this.columnSpliceMapping = new Map()
this.columnSpliceReferences = new Set()

for (const [sidecarKey, hedData] of this.parsedHedData) {
if (hedData instanceof ParsedHedString) {
this._parseValueSplice(sidecarKey, hedData)
this.#parseValueSplice(sidecarKey, hedData)
} else if (hedData instanceof Map) {
this._parseCategorySplice(sidecarKey, hedData)
this.#parseCategorySplice(sidecarKey, hedData)
} else if (hedData) {
IssueError.generateAndThrowInternalError('Unexpected type found in bidsFile parsedHedData map.')
IssueError.generateAndThrowInternalError('Unexpected type found in sidecar parsedHedData map.')
}
}
}

_parseValueSplice(sidecarKey, hedData) {
#parseValueSplice(sidecarKey, hedData) {
if (hedData.columnSplices.length > 0) {
const keyReferences = this._processColumnSplices(new Set(), hedData.columnSplices)
const keyReferences = this.#processColumnSplices(new Set(), hedData.columnSplices)
this.columnSpliceMapping.set(sidecarKey, keyReferences)
}
}

_parseCategorySplice(sidecarKey, hedData) {
#parseCategorySplice(sidecarKey, hedData) {
let keyReferences = null
for (const valueString of hedData.values()) {
if (valueString?.columnSplices.length > 0) {
keyReferences = this._processColumnSplices(keyReferences, valueString.columnSplices)
keyReferences = this.#processColumnSplices(keyReferences, valueString.columnSplices)
}
}
if (keyReferences instanceof Set) {
Expand All @@ -256,7 +267,7 @@ export class BidsSidecar extends BidsJsonFile {
* @returns {Set<string>}
* @private
*/
_processColumnSplices(keyReferences, columnSplices) {
#processColumnSplices(keyReferences, columnSplices) {
keyReferences ??= new Set()
for (const columnSplice of columnSplices) {
keyReferences.add(columnSplice.originalTag)
Expand Down Expand Up @@ -306,7 +317,7 @@ export class BidsSidecarKey {
parsedValueString

/**
* Weak reference to the bidsFile.
* Weak reference to the sidecar.
* @type {BidsSidecar}
*/
sidecar
Expand All @@ -322,7 +333,7 @@ export class BidsSidecarKey {
*
* @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.
* @param {BidsSidecar} sidecar The parent sidecar.
*/
constructor(key, data, sidecar) {
this.name = key
Expand All @@ -347,13 +358,13 @@ export class BidsSidecarKey {
*/
parseHed(hedSchemas) {
if (this.isValueKey) {
return this._parseValueString(hedSchemas)
return this.#parseValueString(hedSchemas)
}
return this._parseCategory(hedSchemas)
return this.#parseCategory(hedSchemas)
}

/**
* Parse the value string in a bidsFile.
* Parse the value string in a sidecar.
*
* ### Note:
* The value strings cannot contain definitions.
Expand All @@ -362,7 +373,7 @@ export class BidsSidecarKey {
* @returns {Array} - [Issue[], Issue[]] - Errors due for the value.
* @private
*/
_parseValueString(hedSchemas) {
#parseValueString(hedSchemas) {
const [parsedString, errorIssues, warningIssues] = parseHedString(this.valueString, hedSchemas, false, true)
this.parsedValueString = parsedString
return [errorIssues, warningIssues]
Expand All @@ -374,7 +385,7 @@ export class BidsSidecarKey {
* @returns {Array} - Array[Issue[], Issue[]] A list of error issues and warning issues.
* @private
*/
_parseCategory(hedSchemas) {
#parseCategory(hedSchemas) {
this.parsedCategoryMap = new Map()
const errors = []
const warnings = []
Expand All @@ -393,7 +404,7 @@ export class BidsSidecarKey {
warnings.push(...warningIssues)
errors.push(...errorIssues)
if (errorIssues.length === 0) {
errors.push(...this._checkDefinitions(parsedString))
errors.push(...this.#checkDefinitions(parsedString))
}
}
return [errors, warnings]
Expand All @@ -405,7 +416,7 @@ export class BidsSidecarKey {
* @returns {Issue[]} - Errors that occur.
* @private
*/
_checkDefinitions(parsedString) {
#checkDefinitions(parsedString) {
const errors = []
for (const group of parsedString.tagGroups) {
if (!group.isDefinitionGroup) {
Expand Down
4 changes: 2 additions & 2 deletions src/bids/types/tsv.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class BidsTsvFile extends BidsFile {
hedColumnHedStrings

/**
* The pseudo-bidsFile object representing the merged bidsFile data.
* The pseudo-sidecar object representing the merged sidecar data.
* @type {BidsSidecar}
*/
mergedSidecar
Expand All @@ -34,7 +34,7 @@ export class BidsTsvFile extends BidsFile {
* @param {string} name - The name of the TSV file.
* @param {Object} file - The file object representing this file.
* @param {{headers: string[], rows: string[][]}|Map|string} tsvData - This file's TSV data.
* @param {Object} mergedDictionary - The merged bidsFile data.
* @param {Object} mergedDictionary - The merged sidecar data.
* @param {DefinitionManager} defManager - The definition manager for this file.
*/
constructor(name, file, tsvData, mergedDictionary = {}, defManager = undefined) {
Expand Down
Loading
Loading