bids-validator-deno 2.0.8__tar.gz → 2.0.10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bids-validator-deno might be problematic. Click here for more details.
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/PKG-INFO +1 -1
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/deno.json +2 -2
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/pyproject.toml +1 -1
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/inheritance.ts +0 -1
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/json.test.ts +3 -3
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/json.ts +11 -3
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/nifti.test.ts +1 -1
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/nifti.ts +2 -2
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/tsv.test.ts +3 -3
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/tsv.ts +7 -3
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/issues/list.ts +8 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/main.ts +1 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/applyRules.ts +7 -2
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/associations.ts +2 -2
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/context.ts +18 -13
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/tables.test.ts +73 -0
- bids_validator_deno-2.0.10/src/schema/tables.ts +403 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/setup/options.test.ts +1 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/setup/options.ts +12 -1
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/summary/collectSubjectMetadata.ts +2 -2
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/regression.test.ts +2 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/validation-result.ts +1 -1
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/bids.test.ts +5 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/bids.ts +14 -2
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/hed.ts +7 -1
- bids_validator_deno-2.0.8/src/schema/tables.ts +0 -323
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/LICENSE +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/README.md +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/pdm_build.py +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/.git-meta.json +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/bids-validator.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/browser.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/browser.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/deno.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/deno.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/dwi.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/dwi.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/filetree.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/filetree.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/gzip.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/gzip.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/ignore.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/ignore.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/inheritance.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/streams.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/streams.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/tiff.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/tiff.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/issues/datasetIssues.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/issues/datasetIssues.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/issues/list.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/applyRules.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/context.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/entities.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/entities.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/expressionLanguage.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/expressionLanguage.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/fixtures.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/modalities.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/walk.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/walk.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/setup/loadSchema.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/setup/loadSchema.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/setup/requestPermissions.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/summary/summary.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/summary/summary.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/README.md +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/bom-utf16.tsv +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/bom-utf8.json +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/generate-filenames.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/bids_examples.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/common.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/derivatives.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/empty_files.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/hed-integration.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/valid_dataset.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/valid_filenames.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/valid_headers.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/nullReadBytes.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/schema-expression-language.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/simple-dataset.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/utils.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/check.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/columns.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/columns.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/filetree.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/issues.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/schema.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/errors.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/logger.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/logger.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/memoize.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/objectPathHandler.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/output.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/citation.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/citation.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/filenameIdentify.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/filenameIdentify.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/filenameValidate.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/filenameValidate.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/internal/emptyFile.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/internal/unusedFile.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/json.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/validateFiles.test.ts +0 -0
- {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/version.ts +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bids/validator",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.10",
|
|
4
4
|
"exports": {
|
|
5
5
|
".": "./src/bids-validator.ts",
|
|
6
6
|
"./main": "./src/main.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"imports": {
|
|
30
30
|
"@ajv": "npm:ajv@8.17.1",
|
|
31
|
-
"@bids/schema": "jsr:@bids/schema
|
|
31
|
+
"@bids/schema": "jsr:@bids/schema@~1.0.14",
|
|
32
32
|
"@cliffy/command": "jsr:@effigies/cliffy-command@1.0.0-dev.8",
|
|
33
33
|
"@cliffy/table": "jsr:@effigies/cliffy-table@1.0.0-dev.5",
|
|
34
34
|
"@hed/validator": "npm:hed-validator@4.0.1",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { BIDSFile, FileTree } from '../types/filetree.ts'
|
|
2
2
|
import { readEntities } from '../schema/entities.ts'
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
type Ret<T> = T extends [string, ...string[]] ? (BIDSFile | BIDSFile[]) : BIDSFile
|
|
6
5
|
|
|
7
6
|
/** Find associated files in order of proximity to a source file.
|
|
@@ -40,7 +40,7 @@ Deno.test('Test JSON error conditions', async (t) => {
|
|
|
40
40
|
await loadJSON(BOMfile).catch((e) => {
|
|
41
41
|
error = e
|
|
42
42
|
})
|
|
43
|
-
assertObjectMatch(error, {
|
|
43
|
+
assertObjectMatch(error, { code: 'INVALID_JSON_ENCODING' })
|
|
44
44
|
})
|
|
45
45
|
|
|
46
46
|
await t.step('Error on UTF-16', async () => {
|
|
@@ -49,7 +49,7 @@ Deno.test('Test JSON error conditions', async (t) => {
|
|
|
49
49
|
await loadJSON(UTF16file).catch((e) => {
|
|
50
50
|
error = e
|
|
51
51
|
})
|
|
52
|
-
assertObjectMatch(error, {
|
|
52
|
+
assertObjectMatch(error, { code: 'INVALID_JSON_ENCODING' })
|
|
53
53
|
})
|
|
54
54
|
|
|
55
55
|
await t.step('Error on invalid JSON syntax', async () => {
|
|
@@ -58,6 +58,6 @@ Deno.test('Test JSON error conditions', async (t) => {
|
|
|
58
58
|
await loadJSON(badJSON).catch((e) => {
|
|
59
59
|
error = e
|
|
60
60
|
})
|
|
61
|
-
assertObjectMatch(error, {
|
|
61
|
+
assertObjectMatch(error, { code: 'JSON_INVALID' })
|
|
62
62
|
})
|
|
63
63
|
})
|
|
@@ -14,7 +14,7 @@ async function readJSONText(file: BIDSFile): Promise<string> {
|
|
|
14
14
|
}
|
|
15
15
|
return text
|
|
16
16
|
} catch (error) {
|
|
17
|
-
throw {
|
|
17
|
+
throw { code: 'INVALID_JSON_ENCODING' }
|
|
18
18
|
} finally {
|
|
19
19
|
decoder.decode() // Reset decoder
|
|
20
20
|
}
|
|
@@ -22,9 +22,17 @@ async function readJSONText(file: BIDSFile): Promise<string> {
|
|
|
22
22
|
|
|
23
23
|
export async function loadJSON(file: BIDSFile): Promise<Record<string, unknown>> {
|
|
24
24
|
const text = await readJSONText(file) // Raise encoding errors
|
|
25
|
+
let parsedText
|
|
25
26
|
try {
|
|
26
|
-
|
|
27
|
+
parsedText = JSON.parse(text)
|
|
27
28
|
} catch (error) {
|
|
28
|
-
throw {
|
|
29
|
+
throw { code: 'JSON_INVALID' } // Raise syntax errors
|
|
29
30
|
}
|
|
31
|
+
if (Array.isArray(parsedText) || typeof parsedText !== 'object') {
|
|
32
|
+
throw {
|
|
33
|
+
code: 'JSON_NOT_AN_OBJECT',
|
|
34
|
+
issueMessage: text.substring(0, 10) + (text.length > 10 ? '...' : ''),
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return parsedText
|
|
30
38
|
}
|
|
@@ -51,7 +51,7 @@ Deno.test('Test loading nifti header', async (t) => {
|
|
|
51
51
|
const header = await loadHeader(file).catch((e) => {
|
|
52
52
|
error = e
|
|
53
53
|
})
|
|
54
|
-
assertObjectMatch(error, {
|
|
54
|
+
assertObjectMatch(error, { code: 'NIFTI_HEADER_UNREADABLE' })
|
|
55
55
|
})
|
|
56
56
|
|
|
57
57
|
await t.step('Tolerate big headers', async () => {
|
|
@@ -45,7 +45,7 @@ export async function loadHeader(file: BIDSFile): Promise<NiftiHeader> {
|
|
|
45
45
|
header.readHeader(data.buffer)
|
|
46
46
|
}
|
|
47
47
|
if (!header) {
|
|
48
|
-
throw {
|
|
48
|
+
throw { code: 'NIFTI_HEADER_UNREADABLE' }
|
|
49
49
|
}
|
|
50
50
|
const ndim = header.dims[0]
|
|
51
51
|
return {
|
|
@@ -67,6 +67,6 @@ export async function loadHeader(file: BIDSFile): Promise<NiftiHeader> {
|
|
|
67
67
|
sform_code: header.sform_code,
|
|
68
68
|
} as NiftiHeader
|
|
69
69
|
} catch (err) {
|
|
70
|
-
throw {
|
|
70
|
+
throw { code: 'NIFTI_HEADER_UNREADABLE' }
|
|
71
71
|
}
|
|
72
72
|
}
|
|
@@ -53,7 +53,7 @@ Deno.test('TSV loading', async (t) => {
|
|
|
53
53
|
try {
|
|
54
54
|
await loadTSV(file)
|
|
55
55
|
} catch (e: any) {
|
|
56
|
-
assertObjectMatch(e, {
|
|
56
|
+
assertObjectMatch(e, { code: 'TSV_EMPTY_LINE', line: 3 })
|
|
57
57
|
}
|
|
58
58
|
})
|
|
59
59
|
|
|
@@ -64,7 +64,7 @@ Deno.test('TSV loading', async (t) => {
|
|
|
64
64
|
try {
|
|
65
65
|
await loadTSV(file)
|
|
66
66
|
} catch (e: any) {
|
|
67
|
-
assertObjectMatch(e, {
|
|
67
|
+
assertObjectMatch(e, { code: 'TSV_EQUAL_ROWS', location: '/mismatched_row.tsv', line: 3 })
|
|
68
68
|
}
|
|
69
69
|
})
|
|
70
70
|
|
|
@@ -171,7 +171,7 @@ Deno.test('TSV loading', async (t) => {
|
|
|
171
171
|
await loadTSV(file)
|
|
172
172
|
assert(false, 'Expected error')
|
|
173
173
|
} catch (e: any) {
|
|
174
|
-
assertObjectMatch(e, {
|
|
174
|
+
assertObjectMatch(e, { code: 'TSV_COLUMN_HEADER_DUPLICATE', issueMessage: 'a, a' })
|
|
175
175
|
}
|
|
176
176
|
})
|
|
177
177
|
|
|
@@ -19,7 +19,11 @@ async function _loadTSV(file: BIDSFile, maxRows: number = -1): Promise<ColumnsMa
|
|
|
19
19
|
const headers = (headerRow.done || !headerRow.value) ? [] : headerRow.value.split('\t')
|
|
20
20
|
|
|
21
21
|
if (new Set(headers).size !== headers.length) {
|
|
22
|
-
throw {
|
|
22
|
+
throw {
|
|
23
|
+
code: 'TSV_COLUMN_HEADER_DUPLICATE',
|
|
24
|
+
location: file.path,
|
|
25
|
+
issueMessage: headers.join(', '),
|
|
26
|
+
}
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
// Initialize columns in array for construction efficiency
|
|
@@ -36,12 +40,12 @@ async function _loadTSV(file: BIDSFile, maxRows: number = -1): Promise<ColumnsMa
|
|
|
36
40
|
if (!value) {
|
|
37
41
|
const nextRow = await reader.read()
|
|
38
42
|
if (nextRow.done) break
|
|
39
|
-
throw {
|
|
43
|
+
throw { code: 'TSV_EMPTY_LINE', location: file.path, line: rowIndex + 2 }
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
const values = value.split('\t')
|
|
43
47
|
if (values.length !== headers.length) {
|
|
44
|
-
throw {
|
|
48
|
+
throw { code: 'TSV_EQUAL_ROWS', location: file.path, line: rowIndex + 2 }
|
|
45
49
|
}
|
|
46
50
|
columns.forEach((column, columnIndex) => {
|
|
47
51
|
// Double array size if we exceed the current capacity
|
|
@@ -9,6 +9,10 @@ export const bidsIssues: IssueDefinitionRecord = {
|
|
|
9
9
|
severity: 'error',
|
|
10
10
|
reason: 'Not a valid JSON file.',
|
|
11
11
|
},
|
|
12
|
+
JSON_NOT_AN_OBJECT: {
|
|
13
|
+
severity: 'error',
|
|
14
|
+
reason: 'Parsed JSON file does not contain an object.',
|
|
15
|
+
},
|
|
12
16
|
MISSING_DATASET_DESCRIPTION: {
|
|
13
17
|
severity: 'error',
|
|
14
18
|
reason: 'A dataset_description.json file is required in the root of the dataset',
|
|
@@ -166,6 +170,10 @@ export const bidsIssues: IssueDefinitionRecord = {
|
|
|
166
170
|
severity: 'error',
|
|
167
171
|
reason: 'A json sidecar file was found without a corresponding data file',
|
|
168
172
|
},
|
|
173
|
+
UNSUPPORTED_DATASET_TYPE: {
|
|
174
|
+
severity: 'error',
|
|
175
|
+
reason: 'This DatasetType is not supported by the application.',
|
|
176
|
+
},
|
|
169
177
|
BLACKLISTED_MODALITY: {
|
|
170
178
|
severity: 'error',
|
|
171
179
|
reason: 'The modality in this file is blacklisted through validator configuration.',
|
|
@@ -10,6 +10,7 @@ import { consoleFormat, resultToJSONStr } from './utils/output.ts'
|
|
|
10
10
|
import { setupLogging } from './utils/logger.ts'
|
|
11
11
|
import type { ValidationResult } from './types/validation-result.ts'
|
|
12
12
|
export type { ValidationResult } from './types/validation-result.ts'
|
|
13
|
+
export { getVersion } from './version.ts'
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Validation entrypoint intended for command line usage with Deno
|
|
@@ -94,7 +94,6 @@ export function evalCheck(src: string, context: BIDSContext) {
|
|
|
94
94
|
* We associate theys keys from a rule object to a function adds an
|
|
95
95
|
* issue to the context if the rule evaluation fails.
|
|
96
96
|
*/
|
|
97
|
-
// @ts-expect-error
|
|
98
97
|
const evalMap: Record<
|
|
99
98
|
keyof GenericRule,
|
|
100
99
|
(
|
|
@@ -105,9 +104,13 @@ const evalMap: Record<
|
|
|
105
104
|
) => boolean | void
|
|
106
105
|
> = {
|
|
107
106
|
checks: evalRuleChecks,
|
|
107
|
+
// @ts-expect-error
|
|
108
108
|
columns: evalColumns,
|
|
109
|
+
// @ts-expect-error
|
|
109
110
|
additional_columns: evalAdditionalColumns,
|
|
111
|
+
// @ts-expect-error
|
|
110
112
|
initial_columns: evalInitialColumns,
|
|
113
|
+
// @ts-expect-error
|
|
111
114
|
index_columns: evalIndexColumns,
|
|
112
115
|
fields: evalJsonCheck,
|
|
113
116
|
}
|
|
@@ -183,7 +186,9 @@ function evalJsonCheck(
|
|
|
183
186
|
// Count on other JSON rules to use selectors to match the correct files
|
|
184
187
|
// Text files at the root do not have sidecars. We might want a cleaner
|
|
185
188
|
// or more schematic way to identify them in the future.
|
|
186
|
-
if (sidecarRule && (['.json', '', '.md', '.txt', '.rst', '.cff'].includes(context.extension)))
|
|
189
|
+
if (sidecarRule && (['.json', '', '.md', '.txt', '.rst', '.cff'].includes(context.extension))) {
|
|
190
|
+
return
|
|
191
|
+
}
|
|
187
192
|
|
|
188
193
|
const json: Record<string, any> = sidecarRule ? context.sidecar : context.json
|
|
189
194
|
for (const [key, requirement] of Object.entries(rule.fields)) {
|
|
@@ -143,8 +143,8 @@ export async function buildAssociations(
|
|
|
143
143
|
// @ts-expect-error
|
|
144
144
|
associations[key] = await load(file, { maxRows: context.dataset.options?.maxRows }).catch(
|
|
145
145
|
(error: any) => {
|
|
146
|
-
if (
|
|
147
|
-
context.dataset.issues.add({
|
|
146
|
+
if (error.code) {
|
|
147
|
+
context.dataset.issues.add({ ...error, location: file.path })
|
|
148
148
|
}
|
|
149
149
|
},
|
|
150
150
|
)
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
Subjects,
|
|
10
10
|
Tiff,
|
|
11
11
|
} from '@bids/schema/context'
|
|
12
|
+
import type { Schemas as HedSchemas } from '@hed/validator'
|
|
12
13
|
import type { Schema } from '../types/schema.ts'
|
|
13
14
|
import type { BIDSFile } from '../types/filetree.ts'
|
|
14
15
|
import { FileTree } from '../types/filetree.ts'
|
|
@@ -41,7 +42,7 @@ export class BIDSContextDataset implements Dataset {
|
|
|
41
42
|
opaqueDirectories: Set<string>
|
|
42
43
|
|
|
43
44
|
// Opaque object for HED validator
|
|
44
|
-
hedSchemas:
|
|
45
|
+
hedSchemas: HedSchemas | undefined | null = undefined
|
|
45
46
|
|
|
46
47
|
constructor(
|
|
47
48
|
args: Partial<BIDSContextDataset>,
|
|
@@ -209,8 +210,8 @@ export class BIDSContext implements Context {
|
|
|
209
210
|
}
|
|
210
211
|
for (const file of sidecars) {
|
|
211
212
|
const json = await loadJSON(file).catch((error) => {
|
|
212
|
-
if (error.
|
|
213
|
-
this.dataset.issues.add({
|
|
213
|
+
if (error.code) {
|
|
214
|
+
this.dataset.issues.add({ ...error, location: file.path })
|
|
214
215
|
return {}
|
|
215
216
|
} else {
|
|
216
217
|
throw error
|
|
@@ -231,8 +232,8 @@ export class BIDSContext implements Context {
|
|
|
231
232
|
) return
|
|
232
233
|
|
|
233
234
|
this.nifti_header = await loadHeader(this.file).catch((error) => {
|
|
234
|
-
if (error.
|
|
235
|
-
this.dataset.issues.add({
|
|
235
|
+
if (error.code) {
|
|
236
|
+
this.dataset.issues.add({ ...error, location: this.file.path })
|
|
236
237
|
return undefined
|
|
237
238
|
} else {
|
|
238
239
|
throw error
|
|
@@ -247,8 +248,8 @@ export class BIDSContext implements Context {
|
|
|
247
248
|
|
|
248
249
|
this.columns = await loadTSV(this.file, this.dataset.options?.maxRows)
|
|
249
250
|
.catch((error) => {
|
|
250
|
-
if (error.
|
|
251
|
-
this.dataset.issues.add({
|
|
251
|
+
if (error.code) {
|
|
252
|
+
this.dataset.issues.add({ ...error, location: this.file.path })
|
|
252
253
|
}
|
|
253
254
|
logger.warn(
|
|
254
255
|
`tsv file could not be opened by loadColumns '${this.file.path}'`,
|
|
@@ -271,8 +272,8 @@ export class BIDSContext implements Context {
|
|
|
271
272
|
return
|
|
272
273
|
}
|
|
273
274
|
this.json = await loadJSON(this.file).catch((error) => {
|
|
274
|
-
if (error.
|
|
275
|
-
this.dataset.issues.add({
|
|
275
|
+
if (error.code) {
|
|
276
|
+
this.dataset.issues.add({ ...error, location: this.file.path })
|
|
276
277
|
return {}
|
|
277
278
|
} else {
|
|
278
279
|
throw error
|
|
@@ -319,9 +320,10 @@ export class BIDSContext implements Context {
|
|
|
319
320
|
const participants_tsv = this.dataset.tree.get('participants.tsv') as BIDSFile
|
|
320
321
|
if (participants_tsv) {
|
|
321
322
|
const participantsData = await loadTSV(participants_tsv)
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
323
|
+
.catch((error) => {
|
|
324
|
+
return new Map()
|
|
325
|
+
}) as Record<string, string[]>
|
|
326
|
+
this.dataset.subjects.participant_id = participantsData['participant_id']
|
|
325
327
|
}
|
|
326
328
|
|
|
327
329
|
// Load phenotype from phenotype/*.tsv
|
|
@@ -332,7 +334,10 @@ export class BIDSContext implements Context {
|
|
|
332
334
|
const seen = new Set() as Set<string>
|
|
333
335
|
for (const file of phenotypeFiles) {
|
|
334
336
|
const phenotypeData = await loadTSV(file)
|
|
335
|
-
|
|
337
|
+
.catch((error) => {
|
|
338
|
+
return new Map()
|
|
339
|
+
}) as Record<string, string[]>
|
|
340
|
+
const participant_id = phenotypeData['participant_id']
|
|
336
341
|
if (participant_id) {
|
|
337
342
|
participant_id.forEach((id) => seen.add(id))
|
|
338
343
|
}
|
|
@@ -26,6 +26,18 @@ const schemaDefs = {
|
|
|
26
26
|
index_columns: ['filename'],
|
|
27
27
|
additional_columns: 'allowed',
|
|
28
28
|
},
|
|
29
|
+
Participants: {
|
|
30
|
+
selectors: ['path == "/participants.tsv"'],
|
|
31
|
+
initial_columns: ['participant_id'],
|
|
32
|
+
columns: {
|
|
33
|
+
participant_id: 'required',
|
|
34
|
+
age: 'recommended',
|
|
35
|
+
sex: 'recommended',
|
|
36
|
+
strain_rrid: 'recommended',
|
|
37
|
+
},
|
|
38
|
+
index_columns: ['participant_id'],
|
|
39
|
+
additional_columns: 'allowed',
|
|
40
|
+
},
|
|
29
41
|
},
|
|
30
42
|
made_up: {
|
|
31
43
|
MadeUp: {
|
|
@@ -93,6 +105,67 @@ Deno.test('tables eval* tests', async (t) => {
|
|
|
93
105
|
assertEquals(context.dataset.issues.size, 0)
|
|
94
106
|
})
|
|
95
107
|
|
|
108
|
+
await t.step('verify column override behavior', () => {
|
|
109
|
+
const context = {
|
|
110
|
+
path: '/participants.tsv',
|
|
111
|
+
extension: '.tsv',
|
|
112
|
+
sidecar: {
|
|
113
|
+
participant_id: {
|
|
114
|
+
Description: 'A participant identifier',
|
|
115
|
+
Format: 'string',
|
|
116
|
+
},
|
|
117
|
+
age: {
|
|
118
|
+
Description: 'Age in weeks',
|
|
119
|
+
Format: 'number',
|
|
120
|
+
},
|
|
121
|
+
sex: {
|
|
122
|
+
Description: 'Phenotypic sex',
|
|
123
|
+
Format: 'string',
|
|
124
|
+
Levels: {
|
|
125
|
+
'F': { Description: 'Female' },
|
|
126
|
+
'M': { Description: 'Male' },
|
|
127
|
+
'O': { Description: 'Other' },
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
strain_rrid: {
|
|
131
|
+
Description: 'Invalid override',
|
|
132
|
+
Format: 'integer',
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
sidecarKeyOrigin: {
|
|
136
|
+
participant_id: '/participants.json',
|
|
137
|
+
age: '/participants.json',
|
|
138
|
+
sex: '/participants.json',
|
|
139
|
+
strain_rrid: '/participants.json',
|
|
140
|
+
},
|
|
141
|
+
columns: {
|
|
142
|
+
participant_id: ['sub-01', 'sub-02', 'sub-03'],
|
|
143
|
+
age: ['10', '20', '30'],
|
|
144
|
+
sex: ['M', 'F', 'f'],
|
|
145
|
+
strain_rrid: ['RRID:SCR_012345', 'RRID:SCR_012345', 'n/a'],
|
|
146
|
+
},
|
|
147
|
+
dataset: { issues: new DatasetIssues() },
|
|
148
|
+
}
|
|
149
|
+
const rule = schemaDefs.rules.tabular_data.modality_agnostic.Participants
|
|
150
|
+
evalColumns(rule, context, schema, 'rules.tabular_data.modality_agnostic.Participants')
|
|
151
|
+
|
|
152
|
+
// participant_id column definition is compatible with schema
|
|
153
|
+
// age and sex may be overridden
|
|
154
|
+
// strain_rrid can't be redefined to numeric
|
|
155
|
+
let issues = context.dataset.issues.get({ code: 'TSV_COLUMN_TYPE_REDEFINED' })
|
|
156
|
+
assertEquals(issues.length, 1)
|
|
157
|
+
assertEquals(issues[0].subCode, 'strain_rrid')
|
|
158
|
+
assertEquals(issues[0].issueMessage, 'Format "integer" must be rrid')
|
|
159
|
+
|
|
160
|
+
// Overriding the default sex definition uses the provided values
|
|
161
|
+
// Values in the default definition may raise issues
|
|
162
|
+
issues = context.dataset.issues.get({ code: 'TSV_VALUE_INCORRECT_TYPE_NONREQUIRED' })
|
|
163
|
+
assertEquals(issues.length, 1)
|
|
164
|
+
assertEquals(issues[0].subCode, 'sex')
|
|
165
|
+
assertEquals(issues[0].line, 4)
|
|
166
|
+
assertEquals(issues[0].issueMessage, "'f'")
|
|
167
|
+
})
|
|
168
|
+
|
|
96
169
|
await t.step('verify column ordering', () => {
|
|
97
170
|
const context = {
|
|
98
171
|
path: '/sub-01/sub-01_scans.tsv',
|