diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 46a32e3dd..f733c7a52 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,12 +2,12 @@ # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 updates: - - package-ecosystem: "github-actions" - directory: "/" + - package-ecosystem: 'github-actions' + directory: '/' schedule: - interval: "monthly" + interval: 'monthly' - - package-ecosystem: "gitsubmodule" - directory: "/" + - package-ecosystem: 'gitsubmodule' + directory: '/' schedule: - interval: "monthly" + interval: 'monthly' diff --git a/bids-validator/package.json b/bids-validator/package.json index c868f1c1e..35b32a623 100644 --- a/bids-validator/package.json +++ b/bids-validator/package.json @@ -44,7 +44,7 @@ "date-fns": "^2.7.0", "events": "^3.3.0", "exifreader": "^4.1.0", - "hed-validator": "^3.7.1", + "hed-validator": "^3.8.0", "ignore": "^4.0.2", "is-utf8": "^0.2.1", "jshint": "^2.9.6", diff --git a/bids-validator/src/files/deno.test.ts b/bids-validator/src/files/deno.test.ts index 764e58e67..2318f69c1 100644 --- a/bids-validator/src/files/deno.test.ts +++ b/bids-validator/src/files/deno.test.ts @@ -14,7 +14,7 @@ const testDir = dirname(testPath) const testFilename = basename(testPath) const ignore = new FileIgnoreRulesDeno([]) -Deno.test('Deno implementation of BIDSFile', async t => { +Deno.test('Deno implementation of BIDSFile', async (t) => { await t.step('implements basic file properties', () => { const file = new BIDSFileDeno(testDir, testFilename, ignore) assertEquals(join(testDir, file.path), testPath) @@ -45,7 +45,8 @@ Deno.test('Deno implementation of BIDSFile', async t => { const bomFilename = 'bom-utf16.tsv' const file = new BIDSFileDeno(bomDir, bomFilename, ignore) await assertRejects(async () => file.text(), UnicodeDecodeError) - }) + }, + ) await t.step( 'strips BOM characters when reading UTF-8 via .text()', async () => { diff --git a/bids-validator/src/files/tsv.ts b/bids-validator/src/files/tsv.ts index a9bfa5f45..ab8950bb5 100644 --- a/bids-validator/src/files/tsv.ts +++ b/bids-validator/src/files/tsv.ts @@ -13,10 +13,10 @@ export function parseTSV(contents: string) { const rows: string[][] = normalizeEOL(contents) .split('\n') .filter(isContentfulRow) - .map(str => str.split('\t')) + .map((str) => str.split('\t')) const headers = rows.length ? rows[0] : [] - headers.map(x => (columns[x] = [])) + headers.map((x) => (columns[x] = [])) for (let i = 1; i < rows.length; i++) { for (let j = 0; j < headers.length; j++) { columns[headers[j]].push(rows[i][j]) diff --git a/bids-validator/src/tests/local/valid_dataset.test.ts b/bids-validator/src/tests/local/valid_dataset.test.ts index d93b555cb..da737b135 100644 --- a/bids-validator/src/tests/local/valid_dataset.test.ts +++ b/bids-validator/src/tests/local/valid_dataset.test.ts @@ -4,7 +4,7 @@ import { validatePath, formatAssertIssue } from './common.ts' const PATH = 'tests/data/valid_dataset' -Deno.test('valid_dataset dataset', async t => { +Deno.test('valid_dataset dataset', async (t) => { const { tree, result } = await validatePath(t, PATH) await t.step('correctly ignores .bidsignore files', () => { diff --git a/bids-validator/src/tests/local/valid_filenames.test.ts b/bids-validator/src/tests/local/valid_filenames.test.ts index a9065cc97..a44fbeff5 100644 --- a/bids-validator/src/tests/local/valid_filenames.test.ts +++ b/bids-validator/src/tests/local/valid_filenames.test.ts @@ -4,7 +4,7 @@ import { validatePath, formatAssertIssue } from './common.ts' const PATH = 'tests/data/valid_filenames' -Deno.test('valid_filenames dataset', async t => { +Deno.test('valid_filenames dataset', async (t) => { const { tree, result } = await validatePath(t, PATH) await t.step('correctly ignores .bidsignore files', () => { diff --git a/bids-validator/src/tests/local/valid_headers.test.ts b/bids-validator/src/tests/local/valid_headers.test.ts index 2af23d617..0f9831d7f 100644 --- a/bids-validator/src/tests/local/valid_headers.test.ts +++ b/bids-validator/src/tests/local/valid_headers.test.ts @@ -4,7 +4,7 @@ import { validatePath, formatAssertIssue } from './common.ts' const PATH = 'tests/data/valid_headers' -Deno.test('valid_headers dataset', async t => { +Deno.test('valid_headers dataset', async (t) => { const { tree, result } = await validatePath(t, PATH) await t.step('correctly ignores .bidsignore files', () => { diff --git a/bids-validator/tests/events.spec.js b/bids-validator/tests/events.spec.js index b784eb81f..56bc214c8 100644 --- a/bids-validator/tests/events.spec.js +++ b/bids-validator/tests/events.spec.js @@ -184,6 +184,77 @@ describe('Events', function () { }) }) + it('should not throw an issue if a value column is annotated', () => { + const events = [ + { + file: { path: '/sub01/sub01_task-test_events.tsv' }, + path: '/sub01/sub01_task-test_events.tsv', + contents: + 'onset\tduration\ttest\tHED\n' + '7\t3.0\tone\tSpeed/30 mph\n', + }, + ] + const jsonDictionary = { + '/sub01/sub01_task-test_events.json': { + myCodes: { + test: { + HED: { + one: 'Label/#', + }, + }, + }, + }, + '/dataset_description.json': { HEDVersion: '8.0.0' }, + } + + return validate.Events.validateEvents( + events, + [], + headers, + jsonDictionary, + jsonFiles, + '', + ).then((issues) => { + assert.deepStrictEqual(issues, []) + }) + }) + + it('should not throw an issue if a library schema is included', () => { + const events = [ + { + file: { path: '/sub01/sub01_task-test_events.tsv' }, + path: '/sub01/sub01_task-test_events.tsv', + contents: + 'onset\tduration\ttest\tHED\n' + '7\t3.0\tone\tSpeed/30 mph\n', + }, + ] + + const jsonDictionary = { + '/sub01/sub01_task-test_events.json': { + myCodes: { + test: { + HED: { + one: 'ts:Sensory-presentation, Label/#', + }, + }, + }, + }, + '/dataset_description.json': { + HEDVersion: ['8.0.0', 'ts:testlib_1.0.2'], + }, + } + + return validate.Events.validateEvents( + events, + [], + headers, + jsonDictionary, + jsonFiles, + '', + ).then((issues) => { + assert.deepStrictEqual(issues, []) + }) + }) + it('should throw an issue if the HED data is invalid', () => { const events = [ { @@ -218,6 +289,43 @@ describe('Events', function () { }) }) + it('should not throw an issue if multiple library schemas are included', () => { + const events = [ + { + file: { path: '/sub01/sub01_task-test_events.tsv' }, + path: '/sub01/sub01_task-test_events.tsv', + contents: + 'onset\tduration\ttest\tHED\n' + '7\t3.0\tone\tSpeed/30 mph\n', + }, + ] + + const jsonDictionary = { + '/sub01/sub01_task-test_events.json': { + myCodes: { + test: { + HED: { + one: 'ts:Sensory-presentation, Label/#, sc:Sleep-deprivation', + }, + }, + }, + }, + '/dataset_description.json': { + HEDVersion: ['8.0.0', 'ts:testlib_1.0.2', 'sc:score_0.0.1'], + }, + } + + return validate.Events.validateEvents( + events, + [], + headers, + jsonDictionary, + jsonFiles, + '', + ).then((issues) => { + assert.deepStrictEqual(issues, []) + }) + }) + it('should properly issue warnings when appropriate', () => { const events = [ { diff --git a/bids-validator/validators/events/hed.js b/bids-validator/validators/events/hed.js index 3db58bf8a..ce4b54bbe 100644 --- a/bids-validator/validators/events/hed.js +++ b/bids-validator/validators/events/hed.js @@ -1,6 +1,4 @@ import hedValidator from 'hed-validator' -import path from 'path' -import semver from 'semver' import union from 'lodash/union' import utils from '../../utils' import parseTsv from '../tsv/tsvParser' @@ -14,14 +12,24 @@ export default function checkHedStrings(events, jsonContents, jsonFiles, dir) { if (!hedDataExists) { return Promise.resolve([]) } - const dataset = new hedValidator.validator.BidsDataset(eventData, sidecarData) - const [schemaDefinition, schemaDefinitionIssues] = parseHedVersion( - jsonContents, + + const datasetDescription = jsonContents['/dataset_description.json'] + const datasetDescriptionData = new hedValidator.validator.BidsJsonFile( + '/dataset_description.json', + datasetDescription, + getSidecarFileObject('/dataset_description.json', jsonFiles), + ) + const dataset = new hedValidator.validator.BidsDataset( + eventData, + sidecarData, + datasetDescriptionData, dir, ) + // New stuff end does parseHedVersion need to be called anymore? + const schemaDefinitionIssues = parseHedVersion(jsonContents) try { return hedValidator.validator - .validateBidsDataset(dataset, schemaDefinition) + .validateBidsDataset(dataset) .then((hedValidationIssues) => { return schemaDefinitionIssues.concat( convertHedIssuesToBidsIssues(hedValidationIssues), @@ -99,24 +107,14 @@ function sidecarValueHasHed(sidecarValue) { ) } -function parseHedVersion(jsonContents, dir) { - const schemaDefinition = {} +function parseHedVersion(jsonContents) { const datasetDescription = jsonContents['/dataset_description.json'] - const issues = [] if (!(datasetDescription && datasetDescription.HEDVersion)) { - issues.push(new Issue({ code: 109 })) - } else if (semver.valid(datasetDescription.HEDVersion)) { - schemaDefinition.version = datasetDescription.HEDVersion + return [new Issue({ code: 109 })] } else { - schemaDefinition.path = path.join( - path.resolve(dir), - 'sourcedata', - datasetDescription.HEDVersion, - ) + return [] } - - return [schemaDefinition, issues] } function internalHedValidatorIssue(error) { diff --git a/bids-validator/validators/json/schemas/pet.json b/bids-validator/validators/json/schemas/pet.json index 6901e3501..24f5f827a 100644 --- a/bids-validator/validators/json/schemas/pet.json +++ b/bids-validator/validators/json/schemas/pet.json @@ -143,7 +143,7 @@ "items": { "type": "number" } }, "CogAtlasID": { "$ref": "common_definitions.json#/definitions/CogAtlasID" }, - "CogPOID": { "$ref": "common_definitions.json#/definitions/CogPOID" }, + "CogPOID": { "$ref": "common_definitions.json#/definitions/CogPOID" }, "TaskName": { "type": "string" }, @@ -152,7 +152,7 @@ }, "Instructions": { "$ref": "common_definitions.json#/definitions/Instructions" - } + } }, "allOf": [ { diff --git a/package-lock.json b/package-lock.json index df026e818..b6331560e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "date-fns": "^2.7.0", "events": "^3.3.0", "exifreader": "^4.1.0", - "hed-validator": "^3.7.1", + "hed-validator": "^3.8.0", "ignore": "^4.0.2", "is-utf8": "^0.2.1", "jshint": "^2.9.6", @@ -11485,13 +11485,16 @@ } }, "node_modules/hed-validator": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/hed-validator/-/hed-validator-3.7.1.tgz", - "integrity": "sha512-nrOOmEGQ6Pp97aQpql6ICWkJdzqD+qM+kLB1NaEHv16ycS8fOUJvL75UTXIV9TirHQiLVc4LtmKSH+u0kYiXNw==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/hed-validator/-/hed-validator-3.8.0.tgz", + "integrity": "sha512-T0CMJOs02NqKeZsaqnb0TgJdurCQ7zA0VFYgzWPsEIrCFLDw8q18MxtTnyxF+B8Jm9V6Km3SpwtyTcdIl4k3xQ==", "dependencies": { + "buffer": "^6.0.3", "date-and-time": "^0.14.2", "date-fns": "^2.17.0", + "events": "^3.3.0", "lodash": "^4.17.21", + "path": "^0.12.7", "pluralize": "^8.0.0", "semver": "^7.3.4", "then-request": "^6.0.2", @@ -11501,6 +11504,29 @@ "node": ">=12.12.0" } }, + "node_modules/hed-validator/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/hed-validator/node_modules/semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -28097,7 +28123,7 @@ "eslint-plugin-prettier": "^2.6.2", "events": "^3.3.0", "exifreader": "^4.1.0", - "hed-validator": "^3.7.1", + "hed-validator": "^3.8.0", "husky": "^1.0.0-rc.13", "ignore": "^4.0.2", "is-utf8": "^0.2.1", @@ -31372,19 +31398,31 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, "hed-validator": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/hed-validator/-/hed-validator-3.7.1.tgz", - "integrity": "sha512-nrOOmEGQ6Pp97aQpql6ICWkJdzqD+qM+kLB1NaEHv16ycS8fOUJvL75UTXIV9TirHQiLVc4LtmKSH+u0kYiXNw==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/hed-validator/-/hed-validator-3.8.0.tgz", + "integrity": "sha512-T0CMJOs02NqKeZsaqnb0TgJdurCQ7zA0VFYgzWPsEIrCFLDw8q18MxtTnyxF+B8Jm9V6Km3SpwtyTcdIl4k3xQ==", "requires": { + "buffer": "^6.0.3", "date-and-time": "^0.14.2", "date-fns": "^2.17.0", + "events": "^3.3.0", "lodash": "^4.17.21", + "path": "^0.12.7", "pluralize": "^8.0.0", "semver": "^7.3.4", "then-request": "^6.0.2", "xml2js": "^0.4.23" }, "dependencies": { + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",