bids-validator-deno 2.0.5__tar.gz → 2.0.7__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.5 → bids_validator_deno-2.0.7}/PKG-INFO +1 -1
  2. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/deno.json +1 -1
  3. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/pdm_build.py +3 -0
  4. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/pyproject.toml +3 -3
  5. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/bids-validator.ts +1 -1
  6. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/applyRules.ts +3 -1
  7. bids_validator_deno-2.0.7/src/schema/associations.ts +165 -0
  8. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/context.ts +1 -3
  9. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/tables.ts +8 -3
  10. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/summary/collectSubjectMetadata.ts +8 -2
  11. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/types/validation-result.ts +2 -2
  12. bids_validator_deno-2.0.5/src/schema/associations.ts +0 -190
  13. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/LICENSE +0 -0
  14. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/README.md +0 -0
  15. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/.git-meta.json +0 -0
  16. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/browser.test.ts +0 -0
  17. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/browser.ts +0 -0
  18. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/deno.test.ts +0 -0
  19. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/deno.ts +0 -0
  20. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/dwi.test.ts +0 -0
  21. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/dwi.ts +0 -0
  22. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/filetree.test.ts +0 -0
  23. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/filetree.ts +0 -0
  24. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/gzip.test.ts +0 -0
  25. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/gzip.ts +0 -0
  26. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/ignore.test.ts +0 -0
  27. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/ignore.ts +0 -0
  28. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/inheritance.test.ts +0 -0
  29. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/inheritance.ts +0 -0
  30. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/json.test.ts +0 -0
  31. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/json.ts +0 -0
  32. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/nifti.test.ts +0 -0
  33. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/nifti.ts +0 -0
  34. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/streams.test.ts +0 -0
  35. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/streams.ts +0 -0
  36. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/tiff.test.ts +0 -0
  37. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/tiff.ts +0 -0
  38. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/tsv.test.ts +0 -0
  39. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/files/tsv.ts +0 -0
  40. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/issues/datasetIssues.test.ts +0 -0
  41. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/issues/datasetIssues.ts +0 -0
  42. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/issues/list.test.ts +0 -0
  43. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/issues/list.ts +0 -0
  44. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/main.ts +0 -0
  45. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/applyRules.test.ts +0 -0
  46. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/context.test.ts +0 -0
  47. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/entities.test.ts +0 -0
  48. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/entities.ts +0 -0
  49. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/expressionLanguage.test.ts +0 -0
  50. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/expressionLanguage.ts +0 -0
  51. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/fixtures.test.ts +0 -0
  52. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/modalities.ts +0 -0
  53. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/tables.test.ts +0 -0
  54. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/walk.test.ts +0 -0
  55. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/schema/walk.ts +0 -0
  56. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/setup/loadSchema.test.ts +0 -0
  57. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/setup/loadSchema.ts +0 -0
  58. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/setup/options.test.ts +0 -0
  59. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/setup/options.ts +0 -0
  60. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/setup/requestPermissions.ts +0 -0
  61. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/summary/summary.test.ts +0 -0
  62. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/summary/summary.ts +0 -0
  63. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/README.md +0 -0
  64. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/bom-utf16.tsv +0 -0
  65. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/bom-utf8.json +0 -0
  66. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/generate-filenames.ts +0 -0
  67. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/local/bids_examples.test.ts +0 -0
  68. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/local/common.ts +0 -0
  69. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/local/derivatives.test.ts +0 -0
  70. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/local/empty_files.test.ts +0 -0
  71. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/local/hed-integration.test.ts +0 -0
  72. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/local/valid_dataset.test.ts +0 -0
  73. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/local/valid_filenames.test.ts +0 -0
  74. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/local/valid_headers.test.ts +0 -0
  75. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/nullReadBytes.ts +0 -0
  76. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/regression.test.ts +0 -0
  77. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/schema-expression-language.test.ts +0 -0
  78. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/simple-dataset.ts +0 -0
  79. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/tests/utils.ts +0 -0
  80. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/types/check.ts +0 -0
  81. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/types/columns.test.ts +0 -0
  82. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/types/columns.ts +0 -0
  83. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/types/filetree.ts +0 -0
  84. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/types/issues.ts +0 -0
  85. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/types/schema.ts +0 -0
  86. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/utils/errors.ts +0 -0
  87. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/utils/logger.test.ts +0 -0
  88. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/utils/logger.ts +0 -0
  89. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/utils/memoize.ts +0 -0
  90. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/utils/objectPathHandler.ts +0 -0
  91. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/utils/output.ts +0 -0
  92. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/bids.test.ts +0 -0
  93. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/bids.ts +0 -0
  94. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/citation.test.ts +0 -0
  95. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/citation.ts +0 -0
  96. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/filenameIdentify.test.ts +0 -0
  97. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/filenameIdentify.ts +0 -0
  98. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/filenameValidate.test.ts +0 -0
  99. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/filenameValidate.ts +0 -0
  100. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/hed.ts +0 -0
  101. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/internal/emptyFile.ts +0 -0
  102. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/internal/unusedFile.ts +0 -0
  103. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/json.ts +0 -0
  104. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/src/validators/validateFiles.test.ts +0 -0
  105. {bids_validator_deno-2.0.5 → bids_validator_deno-2.0.7}/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.5
3
+ Version: 2.0.7
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.5",
3
+ "version": "2.0.7",
4
4
  "exports": {
5
5
  ".": "./src/bids-validator.ts",
6
6
  "./main": "./src/main.ts",
@@ -27,6 +27,9 @@ def pdm_build_initialize(context):
27
27
  "compile",
28
28
  "-ERNW",
29
29
  "--allow-run",
30
+ # Types are checked elsewhere. Type checking at wheel build
31
+ # is painful if some platforms have newer typescript than others.
32
+ "--no-check",
30
33
  "-o",
31
34
  str(target),
32
35
  "src/bids-validator.ts",
@@ -18,7 +18,7 @@ keywords = [
18
18
  "BIDS validator",
19
19
  ]
20
20
  dynamic = []
21
- version = "2.0.5"
21
+ version = "2.0.7"
22
22
 
23
23
  [project.license]
24
24
  text = "MIT"
@@ -55,8 +55,8 @@ scripts = [
55
55
  build = "cp39-*"
56
56
  skip = "*musllinux* *_i686 *-win32"
57
57
  build-frontend = "build"
58
- manylinux-x86_64-image = "quay.io/pypa/manylinux_2_24_x86_64:latest"
59
- manylinux-aarch64-image = "quay.io/pypa/manylinux_2_24_aarch64:latest"
58
+ manylinux-x86_64-image = "quay.io/pypa/manylinux_2_28_x86_64:latest"
59
+ manylinux-aarch64-image = "quay.io/pypa/manylinux_2_28_aarch64:latest"
60
60
  before-build = "curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh && deno --version"
61
61
  test-command = "bids-validator-deno --version"
62
62
  overrides = [
@@ -4,5 +4,5 @@ const result = await main()
4
4
 
5
5
  const errors = result.issues.get({ severity: 'error' })
6
6
  if (errors.length) {
7
- Deno.exit(1)
7
+ Deno.exit(16)
8
8
  }
@@ -181,7 +181,9 @@ function evalJsonCheck(
181
181
  const sidecarRule = schemaPath.match(/rules\.sidecar/)
182
182
  // Sidecar rules apply specifically to data files, as JSON files cannot have sidecars
183
183
  // Count on other JSON rules to use selectors to match the correct files
184
- if (context.extension === '.json' && sidecarRule) return
184
+ // Text files at the root do not have sidecars. We might want a cleaner
185
+ // or more schematic way to identify them in the future.
186
+ if (sidecarRule && (['.json', '', '.md', '.txt', '.rst', '.cff'].includes(context.extension))) return
185
187
 
186
188
  const json: Record<string, any> = sidecarRule ? context.sidecar : context.json
187
189
  for (const [key, requirement] of Object.entries(rule.fields)) {
@@ -0,0 +1,165 @@
1
+ import type {
2
+ Aslcontext,
3
+ Associations,
4
+ Bval,
5
+ Bvec,
6
+ Channels,
7
+ Coordsystem,
8
+ Events,
9
+ M0Scan,
10
+ Magnitude,
11
+ Magnitude1,
12
+ } from '@bids/schema/context'
13
+ import type { Schema as MetaSchema } from '@bids/schema/metaschema'
14
+
15
+ import type { BIDSFile, FileTree } from '../types/filetree.ts'
16
+ import type { BIDSContext } from './context.ts'
17
+ import type { DatasetIssues } from '../issues/datasetIssues.ts'
18
+ import type { readEntities } from './entities.ts'
19
+ import { loadTSV } from '../files/tsv.ts'
20
+ import { parseBvalBvec } from '../files/dwi.ts'
21
+ import { walkBack } from '../files/inheritance.ts'
22
+ import { evalCheck } from './applyRules.ts'
23
+ import { expressionFunctions } from './expressionLanguage.ts'
24
+
25
+ // type AssociationsLookup = Record<keyof ContextAssociations, { extensions: string[], inherit: boolean, load: ... }
26
+
27
+ /**
28
+ * This object describes associated files for data files in a bids dataset
29
+ * For any given datafile we iterate over every key/value in this object.
30
+ * For each entry we see if any files in the datafiles directory have:
31
+ * - a suffix that matches the key
32
+ * - an extension in the entry's extension array.
33
+ * - that all the files entities and their values match those of the datafile
34
+ * If the entry allows for inheritance we recurse up the filetree looking for other applicable files.
35
+ * The load functions are incomplete, some associations need to read data from a file so they're
36
+ * returning promises for now.
37
+ */
38
+ const associationLookup = {
39
+ events: async (file: BIDSFile, options: { maxRows: number }): Promise<Events> => {
40
+ const columns = await loadTSV(file, options.maxRows)
41
+ .catch((e) => {
42
+ return new Map()
43
+ })
44
+ return {
45
+ path: file.path,
46
+ onset: columns.get('onset') || [],
47
+ }
48
+ },
49
+ aslcontext: async (
50
+ file: BIDSFile,
51
+ options: { maxRows: number },
52
+ ): Promise<Aslcontext> => {
53
+ const columns = await loadTSV(file, options.maxRows)
54
+ .catch((e) => {
55
+ return new Map()
56
+ })
57
+ return {
58
+ path: file.path,
59
+ n_rows: columns.get('volume_type')?.length || 0,
60
+ volume_type: columns.get('volume_type') || [],
61
+ }
62
+ },
63
+ m0scan: (file: BIDSFile, options: any): Promise<M0Scan> => {
64
+ return Promise.resolve({ path: file.path })
65
+ },
66
+ magnitude: (file: BIDSFile, options: any): Promise<Magnitude> => {
67
+ return Promise.resolve({ path: file.path })
68
+ },
69
+ magnitude1: (file: BIDSFile, options: any): Promise<Magnitude1> => {
70
+ return Promise.resolve({ path: file.path })
71
+ },
72
+ bval: async (file: BIDSFile, options: any): Promise<Bval> => {
73
+ const contents = await file.text()
74
+ const rows = parseBvalBvec(contents)
75
+ return {
76
+ path: file.path,
77
+ n_cols: rows ? rows[0].length : 0,
78
+ n_rows: rows ? rows.length : 0,
79
+ // @ts-expect-error values is expected to be a number[], coerce lazily
80
+ values: rows[0],
81
+ }
82
+ },
83
+ bvec: async (file: BIDSFile, options: any): Promise<Bvec> => {
84
+ const contents = await file.text()
85
+ const rows = parseBvalBvec(contents)
86
+
87
+ if (rows.some((row) => row.length !== rows[0].length)) {
88
+ throw { key: 'BVEC_ROW_LENGTH' }
89
+ }
90
+
91
+ return {
92
+ path: file.path,
93
+ n_cols: rows ? rows[0].length : 0,
94
+ n_rows: rows ? rows.length : 0,
95
+ }
96
+ },
97
+ channels: async (file: BIDSFile, options: { maxRows: number }): Promise<Channels> => {
98
+ const columns = await loadTSV(file, options.maxRows)
99
+ .catch((e) => {
100
+ return new Map()
101
+ })
102
+ return {
103
+ path: file.path,
104
+ type: columns.get('type'),
105
+ short_channel: columns.get('short_channel'),
106
+ sampling_frequency: columns.get('sampling_frequency'),
107
+ }
108
+ },
109
+ coordsystem: (file: BIDSFile, options: any): Promise<Coordsystem> => {
110
+ return Promise.resolve({ path: file.path })
111
+ },
112
+ }
113
+
114
+ export async function buildAssociations(
115
+ context: BIDSContext,
116
+ ): Promise<Associations> {
117
+ const associations: Associations = {}
118
+
119
+ const schema: MetaSchema = context.dataset.schema as MetaSchema
120
+
121
+ Object.assign(context, expressionFunctions)
122
+ // @ts-expect-error
123
+ context.exists.bind(context)
124
+
125
+ for (const [key, rule] of Object.entries(schema.meta.associations)) {
126
+ if (!rule.selectors!.every((x) => evalCheck(x, context))) {
127
+ continue
128
+ }
129
+ let file
130
+ let extension: string[] = []
131
+ if (typeof rule.target.extension === 'string') {
132
+ extension = [rule.target.extension]
133
+ } else if (Array.isArray(rule.target.extension)) {
134
+ extension = rule.target.extension
135
+ }
136
+ try {
137
+ file = walkBack(context.file, rule.inherit, extension, rule.target.suffix).next().value
138
+ } catch (error) {
139
+ if (
140
+ error && typeof error === 'object' && 'code' in error &&
141
+ error.code === 'MULTIPLE_INHERITABLE_FILES'
142
+ ) {
143
+ // @ts-expect-error
144
+ context.dataset.issues.add(error)
145
+ break
146
+ } else {
147
+ throw error
148
+ }
149
+ }
150
+
151
+ if (file) {
152
+ // @ts-expect-error
153
+ const load = associationLookup[key]
154
+ // @ts-expect-error
155
+ associations[key] = await load(file, { maxRows: context.dataset.options?.maxRows }).catch(
156
+ (error: any) => {
157
+ if (key in error) {
158
+ context.dataset.issues.add({ code: error.key, location: file.path })
159
+ }
160
+ },
161
+ )
162
+ }
163
+ }
164
+ return Promise.resolve(associations)
165
+ }
@@ -261,9 +261,7 @@ export class BIDSContext implements Context {
261
261
 
262
262
  async loadAssociations(): Promise<void> {
263
263
  this.associations = await buildAssociations(
264
- this.file,
265
- this.dataset.issues,
266
- this.dataset.options?.maxRows,
264
+ this,
267
265
  )
268
266
  return
269
267
  }
@@ -239,6 +239,11 @@ export function evalAdditionalColumns(
239
239
  if (context.extension !== '.tsv') return
240
240
  const headers = Object.keys(context?.columns)
241
241
  if (rule.columns) {
242
+ if (!rule.additional_columns || rule.additional_columns === 'n/a' ) {
243
+ // Old schemas might be missing the field, so be permissive.
244
+ // New schemas indicate it is not applicable with 'n/a'.
245
+ return
246
+ }
242
247
  const ruleHeadersNames = Object.keys(rule.columns).map(
243
248
  // @ts-expect-error
244
249
  (x) => schema.objects.columns[x].name,
@@ -250,11 +255,11 @@ export function evalAdditionalColumns(
250
255
  if (rule.additional_columns?.startsWith('allowed')) {
251
256
  extraCols = extraCols.filter((header) => !(header in context.sidecar))
252
257
  }
253
- const code = rule.additional_columns === 'allowed'
254
- ? 'TSV_ADDITIONAL_COLUMNS_UNDEFINED'
258
+ const code = rule.additional_columns === 'not_allowed'
259
+ ? 'TSV_ADDITIONAL_COLUMNS_NOT_ALLOWED'
255
260
  : rule.additional_columns === 'allowed_if_defined'
256
261
  ? 'TSV_ADDITIONAL_COLUMNS_MUST_DEFINE'
257
- : 'TSV_ADDITIONAL_COLUMNS_NOT_ALLOWED'
262
+ : 'TSV_ADDITIONAL_COLUMNS_UNDEFINED'
258
263
  const issue = {
259
264
  code,
260
265
  location: context.path,
@@ -53,8 +53,14 @@ export const collectSubjectMetadata = (
53
53
  '',
54
54
  )
55
55
  // make age an integer
56
- // @ts-expect-error
57
- if (ageKey) data[ageKey.index] = parseInt(data[ageKey.index])
56
+ if (ageKey) {
57
+ if(data[ageKey.index] === "89+") {
58
+ data[ageKey.index] = "89+"
59
+ } else {
60
+ // @ts-expect-error
61
+ data[ageKey.index] = parseFloat(data[ageKey.index])
62
+ }
63
+ }
58
64
  return data
59
65
  })
60
66
  .map((data) =>
@@ -2,8 +2,8 @@ import type { DatasetIssues } from '../issues/datasetIssues.ts'
2
2
 
3
3
  export interface SubjectMetadata {
4
4
  participantId: string
5
- age: number
6
- sex: string
5
+ age?: number | null | "89+"
6
+ sex?: string
7
7
  }
8
8
  /*
9
9
  BodyPart: {},
@@ -1,190 +0,0 @@
1
- import type {
2
- Aslcontext,
3
- Associations,
4
- Bval,
5
- Bvec,
6
- Channels,
7
- Coordsystem,
8
- Events,
9
- M0Scan,
10
- Magnitude,
11
- Magnitude1,
12
- } from '@bids/schema/context'
13
- import type { BIDSFile, FileTree } from '../types/filetree.ts'
14
- import type { BIDSContext } from './context.ts'
15
- import type { DatasetIssues } from '../issues/datasetIssues.ts'
16
- import type { readEntities } from './entities.ts'
17
- import { loadTSV } from '../files/tsv.ts'
18
- import { parseBvalBvec } from '../files/dwi.ts'
19
- import { walkBack } from '../files/inheritance.ts'
20
-
21
- // type AssociationsLookup = Record<keyof ContextAssociations, { extensions: string[], inherit: boolean, load: ... }
22
-
23
- /**
24
- * This object describes associated files for data files in a bids dataset
25
- * For any given datafile we iterate over every key/value in this object.
26
- * For each entry we see if any files in the datafiles directory have:
27
- * - a suffix that matches the key
28
- * - an extension in the entry's extension array.
29
- * - that all the files entities and their values match those of the datafile
30
- * If the entry allows for inheritance we recurse up the filetree looking for other applicable files.
31
- * The load functions are incomplete, some associations need to read data from a file so they're
32
- * returning promises for now.
33
- */
34
- const associationLookup = {
35
- events: {
36
- suffix: 'events',
37
- extensions: ['.tsv'],
38
- inherit: true,
39
- load: async (file: BIDSFile, options: { maxRows: number }): Promise<Events> => {
40
- const columns = await loadTSV(file, options.maxRows)
41
- .catch((e) => {
42
- return new Map()
43
- })
44
- return {
45
- path: file.path,
46
- onset: columns.get('onset') || [],
47
- }
48
- },
49
- },
50
- aslcontext: {
51
- suffix: 'aslcontext',
52
- extensions: ['.tsv'],
53
- inherit: true,
54
- load: async (
55
- file: BIDSFile,
56
- options: { maxRows: number },
57
- ): Promise<Aslcontext> => {
58
- const columns = await loadTSV(file, options.maxRows)
59
- .catch((e) => {
60
- return new Map()
61
- })
62
- return {
63
- path: file.path,
64
- n_rows: columns.get('volume_type')?.length || 0,
65
- volume_type: columns.get('volume_type') || [],
66
- }
67
- },
68
- },
69
- m0scan: {
70
- suffix: 'm0scan',
71
- extensions: ['.nii', '.nii.gz'],
72
- inherit: false,
73
- load: (file: BIDSFile, options: any): Promise<M0Scan> => {
74
- return Promise.resolve({ path: file.path })
75
- },
76
- },
77
- magnitude: {
78
- suffix: 'magnitude',
79
- extensions: ['.nii', '.nii.gz'],
80
- inherit: false,
81
- load: (file: BIDSFile, options: any): Promise<Magnitude> => {
82
- return Promise.resolve({ path: file.path })
83
- },
84
- },
85
- magnitude1: {
86
- suffix: 'magnitude1',
87
- extensions: ['.nii', '.nii.gz'],
88
- inherit: false,
89
- load: (file: BIDSFile, options: any): Promise<Magnitude1> => {
90
- return Promise.resolve({ path: file.path })
91
- },
92
- },
93
- bval: {
94
- suffix: 'dwi',
95
- extensions: ['.bval'],
96
- inherit: true,
97
- load: async (file: BIDSFile, options: any): Promise<Bval> => {
98
- const contents = await file.text()
99
- const rows = parseBvalBvec(contents)
100
- return {
101
- path: file.path,
102
- n_cols: rows ? rows[0].length : 0,
103
- n_rows: rows ? rows.length : 0,
104
- // @ts-expect-error values is expected to be a number[], coerce lazily
105
- values: rows[0],
106
- }
107
- },
108
- },
109
- bvec: {
110
- suffix: 'dwi',
111
- extensions: ['.bvec'],
112
- inherit: true,
113
- load: async (file: BIDSFile, options: any): Promise<Bvec> => {
114
- const contents = await file.text()
115
- const rows = parseBvalBvec(contents)
116
-
117
- if (rows.some((row) => row.length !== rows[0].length)) {
118
- throw { key: 'BVEC_ROW_LENGTH' }
119
- }
120
-
121
- return {
122
- path: file.path,
123
- n_cols: rows ? rows[0].length : 0,
124
- n_rows: rows ? rows.length : 0,
125
- }
126
- },
127
- },
128
- channels: {
129
- suffix: 'channels',
130
- extensions: ['.tsv'],
131
- inherit: true,
132
- load: async (file: BIDSFile, options: { maxRows: number }): Promise<Channels> => {
133
- const columns = await loadTSV(file, options.maxRows)
134
- .catch((e) => {
135
- return new Map()
136
- })
137
- return {
138
- path: file.path,
139
- type: columns.get('type'),
140
- short_channel: columns.get('short_channel'),
141
- sampling_frequency: columns.get('sampling_frequency'),
142
- }
143
- },
144
- },
145
- coordsystem: {
146
- suffix: 'coordsystem',
147
- extensions: ['.json'],
148
- inherit: true,
149
- load: (file: BIDSFile, options: any): Promise<Coordsystem> => {
150
- return Promise.resolve({ path: file.path })
151
- },
152
- },
153
- }
154
-
155
- export async function buildAssociations(
156
- source: BIDSFile,
157
- issues: DatasetIssues,
158
- maxRows: number = -1,
159
- ): Promise<Associations> {
160
- const associations: Associations = {}
161
-
162
- for (const [key, value] of Object.entries(associationLookup)) {
163
- const { suffix, extensions, inherit, load } = value
164
- let file
165
- try {
166
- file = walkBack(source, inherit, extensions, suffix).next().value
167
- } catch (error) {
168
- if (
169
- error && typeof error === 'object' && 'code' in error &&
170
- error.code === 'MULTIPLE_INHERITABLE_FILES'
171
- ) {
172
- // @ts-expect-error
173
- issues.add(error)
174
- break
175
- } else {
176
- throw error
177
- }
178
- }
179
-
180
- if (file) {
181
- // @ts-expect-error Matching load return value to key is hard
182
- associations[key] = await load(file, { maxRows }).catch((error) => {
183
- if (error.key) {
184
- issues.add({ code: error.key, location: file.path })
185
- }
186
- })
187
- }
188
- }
189
- return Promise.resolve(associations)
190
- }