Skip to content

Commit

Permalink
Implement HED column splicing
Browse files Browse the repository at this point in the history
Also add tests for "n/a" deletion.
  • Loading branch information
happy5214 committed Dec 14, 2023
1 parent 1d6ce5e commit d6eb21e
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 2 deletions.
28 changes: 27 additions & 1 deletion parser/columnSplicer.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ export class ColumnSplicer {
if (replacementString === null) {
return null
}
if (columnName === 'HED') {
return this._spliceHedColumnTemplate()
}
if (replacementString === undefined) {
this.issues.push(generateIssue('undefinedCurlyBraces', { column: columnName }))
return []
Expand All @@ -130,6 +133,18 @@ export class ColumnSplicer {
return replacementString.parseTree
}

/**
* Splice a "HED" column value string in place of a column template.
*
* @returns {ParsedHedSubstring[]} The spliced column substitution.
* @private
*/
_spliceHedColumnTemplate() {
const columnName = 'HED'
const replacementString = this.columnValues.get(columnName)
return this._reparseAndSpliceString(replacementString)
}

/**
* Splice a value-taking replacement string in place of a column template.
*
Expand All @@ -141,7 +156,18 @@ export class ColumnSplicer {
const columnName = columnTemplate.originalTag
const replacementString = this.columnReplacements.get(columnName)
const replacedString = replacementString.hedString.replace('#', this.columnValues.get(columnName))
const [newParsedString, parsingIssues] = parseHedString(replacedString, this.hedSchemas)
return this._reparseAndSpliceString(replacedString)
}

/**
* Re-parse a string to use in splicing.
*
* @param {string} replacementString A new string to parse.
* @returns {ParsedHedSubstring[]} The new string's parse tree.
* @private
*/
_reparseAndSpliceString(replacementString) {
const [newParsedString, parsingIssues] = parseHedString(replacementString, this.hedSchemas)
const flatParsingIssues = Object.values(parsingIssues).flat()
if (flatParsingIssues.length > 0) {
this.issues.push(...flatParsingIssues)
Expand Down
23 changes: 23 additions & 0 deletions tests/bids.spec.data.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,29 @@ const tsvFiles = [
'5.5\t0\tface\tn/a',
],
],
// sub11 - 'n/a' curly brace tests
[
[
Object.assign({}, sidecars[6][0], sidecars[6][2]),
'onset\tduration\tevent_code\tresponse_time\n' + '5.0\t0\tball\tn/a\n',
],
[
Object.assign({}, sidecars[6][0], sidecars[6][4]),
'onset\tduration\tevent_code\tHED\tresponse_time\n' + '5.0\t0\tball\tGreen,Def/MyColor\tn/a\n',
],
[
Object.assign({}, sidecars[6][0], sidecars[6][4]),
'onset\tduration\tevent_code\tHED\tresponse_time\n' + '5.0\t0\tball\tn/a\t1\n',
],
[
Object.assign({}, sidecars[6][0], sidecars[6][4]),
'onset\tduration\tevent_code\tHED\tresponse_time\n' + '5.0\t0\tball\tn/a\tn/a\n',
],
[
Object.assign({}, sidecars[6][0], sidecars[6][5]),
'onset\tduration\tevent_code\tresponse_time\tresponse_code\n' + '5.0\t0\tface\t1\tn/a\n',
],
],
]

const datasetDescriptions = [
Expand Down
39 changes: 38 additions & 1 deletion tests/bids.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ const assert = chai.assert
import converterGenerateIssue from '../converter/issues'
import { generateIssue } from '../common/issues/issues'
import { SchemaSpec, SchemasSpec } from '../common/schema/types'
import { parseSchemasSpec } from '../bids/schema'
import { buildBidsSchemas, parseSchemasSpec } from '../bids/schema'
import { BidsDataset, BidsHedIssue, BidsIssue, validateBidsDataset } from '../bids'
import { bidsDatasetDescriptions, bidsSidecars, bidsTsvFiles } from './bids.spec.data'
import { parseHedString } from '../parser/main'
import { BidsHedTsvValidator } from '../bids/validator/bidsHedTsvValidator'

describe('BIDS datasets', () => {
/**
Expand Down Expand Up @@ -675,5 +677,40 @@ describe('BIDS datasets', () => {
}
return validator(testDatasets, expectedIssues, specs)
}, 10000)

it('should delete substrings corresponding to "n/a" TSV values', () => {
const tsvFiles = bidsTsvFiles[10]
const expectedStrings = [
'(Def/Acc/3.5 m-per-s^2)',
'(Def/Acc/3.5 m-per-s^2), (Green, Def/MyColor)',
'Label/1, (Def/Acc/3.5 m-per-s^2)',
'(Def/Acc/3.5 m-per-s^2)',
'(Red, Blue), (Green, (Yellow))',
]
const dataset = new BidsDataset(tsvFiles, [])
return buildBidsSchemas(dataset, specs).then(([hedSchemas, schemaIssues]) => {
assert.isEmpty(schemaIssues, 'Schema failed to load')
const parsedExpectedStrings = []
for (const expectedString of expectedStrings) {
const [parsedExpectedString, parsingIssues] = parseHedString(expectedString, hedSchemas)
assert.isEmpty(Object.values(parsingIssues).flat(), `String "${expectedString}" failed to parse`)
parsedExpectedStrings.push(parsedExpectedString)
}
const tsvHedStrings = []
for (const tsvFile of tsvFiles) {
tsvFile.mergedSidecar.parseHedStrings(hedSchemas)
const tsvValidator = new BidsHedTsvValidator(tsvFile, hedSchemas)
const tsvHed = tsvValidator.parseHed()
assert.isEmpty(tsvValidator.issues, 'TSV file failed to parse')
tsvHedStrings.push(...tsvHed)
}
const formatMap = (hedString) => hedString.format()
assert.deepStrictEqual(
tsvHedStrings.map(formatMap),
parsedExpectedStrings.map(formatMap),
'Mismatch in parsed strings',
)
})
}, 10000)
})
})

0 comments on commit d6eb21e

Please sign in to comment.