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.

Files changed (105) hide show
  1. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/PKG-INFO +1 -1
  2. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/deno.json +2 -2
  3. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/pyproject.toml +1 -1
  4. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/inheritance.ts +0 -1
  5. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/json.test.ts +3 -3
  6. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/json.ts +11 -3
  7. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/nifti.test.ts +1 -1
  8. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/nifti.ts +2 -2
  9. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/tsv.test.ts +3 -3
  10. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/tsv.ts +7 -3
  11. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/issues/list.ts +8 -0
  12. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/main.ts +1 -0
  13. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/applyRules.ts +7 -2
  14. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/associations.ts +2 -2
  15. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/context.ts +18 -13
  16. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/tables.test.ts +73 -0
  17. bids_validator_deno-2.0.10/src/schema/tables.ts +403 -0
  18. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/setup/options.test.ts +1 -0
  19. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/setup/options.ts +12 -1
  20. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/summary/collectSubjectMetadata.ts +2 -2
  21. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/regression.test.ts +2 -0
  22. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/validation-result.ts +1 -1
  23. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/bids.test.ts +5 -0
  24. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/bids.ts +14 -2
  25. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/hed.ts +7 -1
  26. bids_validator_deno-2.0.8/src/schema/tables.ts +0 -323
  27. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/LICENSE +0 -0
  28. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/README.md +0 -0
  29. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/pdm_build.py +0 -0
  30. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/.git-meta.json +0 -0
  31. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/bids-validator.ts +0 -0
  32. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/browser.test.ts +0 -0
  33. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/browser.ts +0 -0
  34. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/deno.test.ts +0 -0
  35. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/deno.ts +0 -0
  36. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/dwi.test.ts +0 -0
  37. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/dwi.ts +0 -0
  38. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/filetree.test.ts +0 -0
  39. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/filetree.ts +0 -0
  40. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/gzip.test.ts +0 -0
  41. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/gzip.ts +0 -0
  42. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/ignore.test.ts +0 -0
  43. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/ignore.ts +0 -0
  44. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/inheritance.test.ts +0 -0
  45. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/streams.test.ts +0 -0
  46. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/streams.ts +0 -0
  47. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/tiff.test.ts +0 -0
  48. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/files/tiff.ts +0 -0
  49. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/issues/datasetIssues.test.ts +0 -0
  50. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/issues/datasetIssues.ts +0 -0
  51. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/issues/list.test.ts +0 -0
  52. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/applyRules.test.ts +0 -0
  53. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/context.test.ts +0 -0
  54. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/entities.test.ts +0 -0
  55. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/entities.ts +0 -0
  56. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/expressionLanguage.test.ts +0 -0
  57. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/expressionLanguage.ts +0 -0
  58. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/fixtures.test.ts +0 -0
  59. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/modalities.ts +0 -0
  60. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/walk.test.ts +0 -0
  61. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/schema/walk.ts +0 -0
  62. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/setup/loadSchema.test.ts +0 -0
  63. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/setup/loadSchema.ts +0 -0
  64. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/setup/requestPermissions.ts +0 -0
  65. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/summary/summary.test.ts +0 -0
  66. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/summary/summary.ts +0 -0
  67. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/README.md +0 -0
  68. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/bom-utf16.tsv +0 -0
  69. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/bom-utf8.json +0 -0
  70. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/generate-filenames.ts +0 -0
  71. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/bids_examples.test.ts +0 -0
  72. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/common.ts +0 -0
  73. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/derivatives.test.ts +0 -0
  74. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/empty_files.test.ts +0 -0
  75. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/hed-integration.test.ts +0 -0
  76. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/valid_dataset.test.ts +0 -0
  77. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/valid_filenames.test.ts +0 -0
  78. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/local/valid_headers.test.ts +0 -0
  79. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/nullReadBytes.ts +0 -0
  80. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/schema-expression-language.test.ts +0 -0
  81. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/simple-dataset.ts +0 -0
  82. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/tests/utils.ts +0 -0
  83. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/check.ts +0 -0
  84. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/columns.test.ts +0 -0
  85. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/columns.ts +0 -0
  86. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/filetree.ts +0 -0
  87. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/issues.ts +0 -0
  88. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/types/schema.ts +0 -0
  89. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/errors.ts +0 -0
  90. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/logger.test.ts +0 -0
  91. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/logger.ts +0 -0
  92. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/memoize.ts +0 -0
  93. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/objectPathHandler.ts +0 -0
  94. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/utils/output.ts +0 -0
  95. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/citation.test.ts +0 -0
  96. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/citation.ts +0 -0
  97. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/filenameIdentify.test.ts +0 -0
  98. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/filenameIdentify.ts +0 -0
  99. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/filenameValidate.test.ts +0 -0
  100. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/filenameValidate.ts +0 -0
  101. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/internal/emptyFile.ts +0 -0
  102. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/internal/unusedFile.ts +0 -0
  103. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/json.ts +0 -0
  104. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/validators/validateFiles.test.ts +0 -0
  105. {bids_validator_deno-2.0.8 → bids_validator_deno-2.0.10}/src/version.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bids-validator-deno
3
- Version: 2.0.8
3
+ Version: 2.0.10
4
4
  Summary: Typescript implementation of the BIDS validator
5
5
  Keywords: BIDS,BIDS validator
6
6
  Author: bids-standard developers
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bids/validator",
3
- "version": "2.0.8",
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@1.0.4",
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",
@@ -18,7 +18,7 @@ keywords = [
18
18
  "BIDS validator",
19
19
  ]
20
20
  dynamic = []
21
- version = "2.0.8"
21
+ version = "2.0.10"
22
22
 
23
23
  [project.license]
24
24
  text = "MIT"
@@ -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, { key: 'INVALID_JSON_ENCODING' })
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, { key: 'INVALID_JSON_ENCODING' })
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, { key: 'JSON_INVALID' })
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 { key: 'INVALID_JSON_ENCODING' }
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
- return JSON.parse(text)
27
+ parsedText = JSON.parse(text)
27
28
  } catch (error) {
28
- throw { key: 'JSON_INVALID' } // Raise syntax errors
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, { key: 'NIFTI_HEADER_UNREADABLE' })
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 { key: 'NIFTI_HEADER_UNREADABLE' }
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 { key: 'NIFTI_HEADER_UNREADABLE' }
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, { key: 'TSV_EMPTY_LINE', line: 3 })
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, { key: 'TSV_EQUAL_ROWS', line: 3 })
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, { key: 'TSV_COLUMN_HEADER_DUPLICATE', evidence: 'a, a' })
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 { key: 'TSV_COLUMN_HEADER_DUPLICATE', evidence: headers.join(', ') }
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 { key: 'TSV_EMPTY_LINE', line: rowIndex + 2 }
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 { key: 'TSV_EQUAL_ROWS', line: rowIndex + 2 }
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))) return
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 (key in error) {
147
- context.dataset.issues.add({ code: error.key, location: file.path })
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: object | undefined | null = undefined
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.key) {
213
- this.dataset.issues.add({ code: error.key, location: file.path })
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.key) {
235
- this.dataset.issues.add({ code: error.key, location: this.file.path })
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.key) {
251
- this.dataset.issues.add({ code: error.key, location: this.file.path })
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.key) {
275
- this.dataset.issues.add({ code: error.key, location: this.file.path })
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
- this.dataset.subjects.participant_id = participantsData[
323
- 'participant_id'
324
- ] as string[]
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
- const participant_id = phenotypeData['participant_id'] as string[]
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',