bids-validator-deno 2.2.0__tar.gz → 2.2.1__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 (115) hide show
  1. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/PKG-INFO +1 -1
  2. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/deno.json +1 -1
  3. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/pyproject.toml +1 -1
  4. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/deno.ts +1 -1
  5. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/filetree.test.ts +2 -9
  6. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/inheritance.ts +18 -0
  7. bids_validator_deno-2.2.1/src/files/openers.test.ts +154 -0
  8. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/tsv.test.ts +21 -38
  9. bids_validator_deno-2.2.1/src/schema/associations.test.ts +32 -0
  10. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/associations.ts +68 -31
  11. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/context.test.ts +16 -4
  12. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/context.ts +11 -20
  13. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/expressionLanguage.test.ts +3 -2
  14. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/fixtures.test.ts +27 -2
  15. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/walk.ts +19 -4
  16. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/hed-integration.test.ts +4 -5
  17. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/regression.test.ts +3 -3
  18. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/utils.ts +0 -6
  19. bids_validator_deno-2.2.1/src/utils/queue.ts +43 -0
  20. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/bids.ts +1 -6
  21. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameIdentify.test.ts +9 -9
  22. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameValidate.test.ts +3 -3
  23. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/validateFiles.test.ts +8 -4
  24. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/LICENSE +0 -0
  25. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/README.md +0 -0
  26. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/pdm_build.py +0 -0
  27. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/.git-meta.json +0 -0
  28. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/bids-validator.ts +0 -0
  29. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/access.test.ts +0 -0
  30. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/access.ts +0 -0
  31. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/browser.test.ts +0 -0
  32. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/browser.ts +0 -0
  33. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/deno.test.ts +0 -0
  34. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/dwi.test.ts +0 -0
  35. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/dwi.ts +0 -0
  36. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/filetree.ts +0 -0
  37. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/gzip.test.ts +0 -0
  38. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/gzip.ts +0 -0
  39. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/ignore.test.ts +0 -0
  40. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/ignore.ts +0 -0
  41. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/inheritance.test.ts +0 -0
  42. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/json.test.ts +0 -0
  43. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/json.ts +0 -0
  44. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/nifti.test.ts +0 -0
  45. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/nifti.ts +0 -0
  46. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/openers.ts +0 -0
  47. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/repo.ts +0 -0
  48. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/streams.test.ts +0 -0
  49. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/streams.ts +0 -0
  50. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/tiff.test.ts +0 -0
  51. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/tiff.ts +0 -0
  52. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/tsv.ts +0 -0
  53. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/issues/datasetIssues.test.ts +0 -0
  54. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/issues/datasetIssues.ts +0 -0
  55. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/issues/list.test.ts +0 -0
  56. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/issues/list.ts +0 -0
  57. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/main.ts +0 -0
  58. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/applyRules.test.ts +0 -0
  59. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/applyRules.ts +0 -0
  60. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/datatypes.test.ts +0 -0
  61. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/datatypes.ts +0 -0
  62. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/entities.test.ts +0 -0
  63. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/entities.ts +0 -0
  64. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/expressionLanguage.ts +0 -0
  65. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/tables.test.ts +0 -0
  66. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/tables.ts +0 -0
  67. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/walk.test.ts +0 -0
  68. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/setup/loadSchema.test.ts +0 -0
  69. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/setup/loadSchema.ts +0 -0
  70. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/setup/options.test.ts +0 -0
  71. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/setup/options.ts +0 -0
  72. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/setup/requestPermissions.ts +0 -0
  73. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/summary/collectSubjectMetadata.ts +0 -0
  74. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/summary/summary.test.ts +0 -0
  75. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/summary/summary.ts +0 -0
  76. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/README.md +0 -0
  77. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/bom-utf16.tsv +0 -0
  78. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/bom-utf8.json +0 -0
  79. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/generate-filenames.ts +0 -0
  80. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/bids_examples.test.ts +0 -0
  81. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/common.ts +0 -0
  82. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/derivatives.test.ts +0 -0
  83. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/empty_files.test.ts +0 -0
  84. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/nifti_rules.test.ts +0 -0
  85. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/valid_dataset.test.ts +0 -0
  86. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/valid_filenames.test.ts +0 -0
  87. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/valid_headers.test.ts +0 -0
  88. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/nullReadBytes.ts +0 -0
  89. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/schema-expression-language.test.ts +0 -0
  90. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/simple-dataset.ts +0 -0
  91. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/check.ts +0 -0
  92. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/columns.test.ts +0 -0
  93. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/columns.ts +0 -0
  94. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/filetree.ts +0 -0
  95. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/issues.ts +0 -0
  96. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/schema.ts +0 -0
  97. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/validation-result.ts +0 -0
  98. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/errors.ts +0 -0
  99. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/logger.test.ts +0 -0
  100. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/logger.ts +0 -0
  101. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/memoize.ts +0 -0
  102. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/objectPathHandler.ts +0 -0
  103. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/output.ts +0 -0
  104. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/bids.test.ts +0 -0
  105. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/citation.test.ts +0 -0
  106. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/citation.ts +0 -0
  107. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameCase.test.ts +0 -0
  108. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameCase.ts +0 -0
  109. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameIdentify.ts +0 -0
  110. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameValidate.ts +0 -0
  111. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/hed.ts +0 -0
  112. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/internal/emptyFile.ts +0 -0
  113. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/internal/unusedFile.ts +0 -0
  114. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/json.ts +0 -0
  115. {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/version.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bids-validator-deno
3
- Version: 2.2.0
3
+ Version: 2.2.1
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.2.0",
3
+ "version": "2.2.1",
4
4
  "exports": {
5
5
  ".": "./src/bids-validator.ts",
6
6
  "./main": "./src/main.ts",
@@ -18,7 +18,7 @@ keywords = [
18
18
  "BIDS validator",
19
19
  ]
20
20
  dynamic = []
21
- version = "2.2.0"
21
+ version = "2.2.1"
22
22
 
23
23
  [project.license]
24
24
  text = "MIT"
@@ -86,7 +86,7 @@ export async function readFileTree(
86
86
  ): Promise<FileTree> {
87
87
  prune ??= new FileIgnoreRules([], false)
88
88
  const ignore = new FileIgnoreRules([])
89
- const tree = await _readFileTree({rootPath, relativePath: '/', ignore, prune, preferredRemote})
89
+ const tree = await _readFileTree({ rootPath, relativePath: '/', ignore, prune, preferredRemote })
90
90
  const bidsignore = tree.get('.bidsignore')
91
91
  if (bidsignore) {
92
92
  try {
@@ -2,18 +2,11 @@ import { assert, assertEquals } from '@std/assert'
2
2
  import { FileIgnoreRules } from './ignore.ts'
3
3
  import { BIDSFile, type FileOpener, type FileTree } from '../types/filetree.ts'
4
4
  import { filesToTree } from './filetree.ts'
5
- import { asyncStreamFromString } from '../tests/utils.ts'
6
-
7
- class NullFileOpener implements FileOpener {
8
- size = 0
9
- stream = () => asyncStreamFromString('')
10
- text = () => Promise.resolve('')
11
- readBytes = async (size: number, offset?: number) => new Uint8Array()
12
- }
5
+ import { StringOpener } from './openers.test.ts'
13
6
 
14
7
  export function pathToFile(path: string, ignored: boolean = false): BIDSFile {
15
8
  const name = path.split('/').pop() as string
16
- return new BIDSFile(path, new NullFileOpener(), ignored)
9
+ return new BIDSFile(path, new StringOpener(''), ignored)
17
10
  }
18
11
 
19
12
  export function pathsToTree(paths: string[], ignore?: string[]): FileTree {
@@ -1,5 +1,6 @@
1
1
  import type { BIDSFile, FileTree } from '../types/filetree.ts'
2
2
  import { readEntities } from '../schema/entities.ts'
3
+ import { loadJSON } from './json.ts'
3
4
 
4
5
  type Ret<T> = T extends [string, ...string[]] ? (BIDSFile | BIDSFile[]) : BIDSFile
5
6
 
@@ -77,3 +78,20 @@ export function* walkBack<T extends string[]>(
77
78
  fileTree = fileTree.parent
78
79
  }
79
80
  }
81
+
82
+ export async function readSidecars(
83
+ source: BIDSFile,
84
+ ): Promise<Map<string, Record<string, unknown>>> {
85
+ const ret: Map<string, Record<string, unknown>> = new Map()
86
+ for (const file of walkBack(source)) {
87
+ try {
88
+ ret.set(file.path, await loadJSON(file))
89
+ } catch (e: any) {
90
+ // Expect JSON parsing errors to be handled when the file is loaded directly
91
+ if (!e?.code) {
92
+ throw e
93
+ }
94
+ }
95
+ }
96
+ return ret
97
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * File openers for use in testing
3
+ */
4
+ import { assertEquals } from '@std/assert'
5
+ import { type FileOpener } from '../types/filetree.ts'
6
+ import { streamFromString } from '../tests/utils.ts'
7
+ import { createUTF8Stream } from './streams.ts'
8
+
9
+ const textEncoder = new TextEncoder()
10
+ const textDecoder = new TextDecoder()
11
+
12
+ export class BytesOpener implements FileOpener {
13
+ contents: Uint8Array<ArrayBuffer>
14
+ size: number
15
+
16
+ constructor(contents: Uint8Array<ArrayBuffer>) {
17
+ this.contents = contents
18
+ this.size = contents.length
19
+ }
20
+
21
+ async text(): Promise<string> {
22
+ return textDecoder.decode(this.contents)
23
+ }
24
+
25
+ async readBytes(size: number, offset = 0): Promise<Uint8Array<ArrayBuffer>> {
26
+ return this.contents.slice(offset, offset + size)
27
+ }
28
+
29
+ async stream(): Promise<ReadableStream<Uint8Array<ArrayBuffer>>> {
30
+ const contents = this.contents
31
+ return new ReadableStream({
32
+ start(controller) {
33
+ controller.enqueue(contents)
34
+ controller.close()
35
+ },
36
+ })
37
+ }
38
+ }
39
+
40
+ export class StringOpener extends BytesOpener {
41
+ constructor(contents: string) {
42
+ super(textEncoder.encode(contents))
43
+ }
44
+ }
45
+
46
+ export class StreamOpener implements FileOpener {
47
+ #stream: ReadableStream<Uint8Array<ArrayBuffer>>
48
+ size: number
49
+
50
+ constructor(stream: ReadableStream<Uint8Array<ArrayBuffer>>, size: number) {
51
+ this.#stream = stream
52
+ this.size = size
53
+ }
54
+
55
+ async stream(): Promise<ReadableStream<Uint8Array<ArrayBuffer>>> {
56
+ const tee = this.#stream.tee()
57
+ this.#stream = tee[1]
58
+ return tee[0]
59
+ }
60
+
61
+ async text(): Promise<string> {
62
+ const stream = await this.stream()
63
+ const reader = stream.pipeThrough(createUTF8Stream()).getReader()
64
+ const chunks: string[] = []
65
+ try {
66
+ while (true) {
67
+ const { done, value } = await reader.read()
68
+ if (done) break
69
+ chunks.push(value)
70
+ }
71
+ return chunks.join('')
72
+ } finally {
73
+ reader.releaseLock()
74
+ }
75
+ }
76
+
77
+ // Not a thoroughly tested implementation
78
+ // Do not move this out of test files without adding more substantial tests
79
+ async readBytes(size: number, offset = 0): Promise<Uint8Array<ArrayBuffer>> {
80
+ const stream = await this.stream()
81
+ const reader = stream.getReader()
82
+ const result = new Uint8Array(size)
83
+ let pos = 0
84
+ try {
85
+ while (pos < offset + size) {
86
+ const { done, value } = await reader.read()
87
+ if (done) break
88
+ if (pos + value.length > offset) {
89
+ result.set(
90
+ value.subarray(Math.max(0, offset - pos), Math.min(value.length, offset + size - pos)),
91
+ Math.max(0, pos - offset),
92
+ )
93
+ }
94
+ pos += value.length
95
+ }
96
+ } finally {
97
+ reader.releaseLock()
98
+ }
99
+ return result.subarray(0, Math.min(size, pos - offset))
100
+ }
101
+ }
102
+
103
+ export class CompressedStringOpener extends StreamOpener {
104
+ constructor(contents: string) {
105
+ // Use uncompressed length as size, for simplicity
106
+ super(streamFromString(contents).pipeThrough(new CompressionStream('gzip')), contents.length)
107
+ }
108
+ }
109
+
110
+ async function testOpener(t: Deno.TestContext, opener: FileOpener) {
111
+ await t.step('size', async () => {
112
+ assertEquals(opener.size, 13)
113
+ })
114
+ await t.step('text()', async () => {
115
+ assertEquals(await opener.text(), 'Hello, world!')
116
+ })
117
+ await t.step('readBytes()', async () => {
118
+ assertEquals(textDecoder.decode(await opener.readBytes(5)), 'Hello')
119
+ assertEquals(textDecoder.decode(await opener.readBytes(7, 5)), ', world')
120
+ })
121
+ await t.step('stream()', async () => {
122
+ const stream = await opener.stream()
123
+ const chunks: string[] = []
124
+ for await (const chunk of stream) {
125
+ chunks.push(textDecoder.decode(chunk))
126
+ }
127
+ assertEquals(chunks.join(''), 'Hello, world!')
128
+ })
129
+ }
130
+
131
+ Deno.test('Validate BytesOpener', async (t) => {
132
+ await testOpener(t, new BytesOpener(textEncoder.encode('Hello, world!')))
133
+ })
134
+
135
+ Deno.test('Validate StringOpener', async (t) => {
136
+ await testOpener(t, new StringOpener('Hello, world!'))
137
+ })
138
+
139
+ Deno.test('Validate StreamOpener', async (t) => {
140
+ await testOpener(t, new StreamOpener(streamFromString('Hello, world!'), 13))
141
+ })
142
+
143
+ Deno.test('Validate CompressedStringOpener', async (t) => {
144
+ const opener = new CompressedStringOpener('Hello, world!')
145
+ await t.step('Decompress', async () => {
146
+ const stream = await opener.stream()
147
+ const decompressedStream = stream.pipeThrough(new DecompressionStream('gzip'))
148
+ const chunks: string[] = []
149
+ for await (const chunk of decompressedStream) {
150
+ chunks.push(textDecoder.decode(chunk))
151
+ }
152
+ assertEquals(chunks.join(''), 'Hello, world!')
153
+ })
154
+ })
@@ -8,22 +8,14 @@ import {
8
8
  import { pathToFile } from './filetree.test.ts'
9
9
  import { BIDSFileDeno } from './deno.ts'
10
10
  import { loadTSV, loadTSVGZ } from './tsv.ts'
11
- import { asyncStreamFromString } from '../tests/utils.ts'
12
11
  import { ColumnsMap } from '../types/columns.ts'
13
12
  import { testAsyncFileAccess } from './access.test.ts'
14
-
15
- async function compressedStreamFromString(
16
- str: string,
17
- ): Promise<ReadableStream<Uint8Array<ArrayBuffer>>> {
18
- return asyncStreamFromString(str).then((stream) =>
19
- stream.pipeThrough(new CompressionStream('gzip')) as ReadableStream<Uint8Array<ArrayBuffer>>
20
- )
21
- }
13
+ import { CompressedStringOpener, StringOpener } from './openers.test.ts'
22
14
 
23
15
  Deno.test('TSV loading', async (t) => {
24
16
  await t.step('Empty file produces empty map', async () => {
25
17
  const file = pathToFile('/empty.tsv')
26
- file.opener.stream = () => asyncStreamFromString('')
18
+ file.opener = new StringOpener('')
27
19
 
28
20
  const map = await loadTSV(file)
29
21
  // map.size looks for a column called map, so work around it
@@ -32,7 +24,7 @@ Deno.test('TSV loading', async (t) => {
32
24
 
33
25
  await t.step('Single row file produces header-only map', async () => {
34
26
  const file = pathToFile('/single_row.tsv')
35
- file.opener.stream = () => asyncStreamFromString('a\tb\tc\n')
27
+ file.opener = new StringOpener('a\tb\tc\n')
36
28
 
37
29
  const map = await loadTSV(file)
38
30
  assertEquals(map.a, [])
@@ -42,7 +34,7 @@ Deno.test('TSV loading', async (t) => {
42
34
 
43
35
  await t.step('Single column file produces single column map', async () => {
44
36
  const file = pathToFile('/single_column.tsv')
45
- file.opener.stream = () => asyncStreamFromString('a\n1\n2\n3\n')
37
+ file.opener = new StringOpener('a\n1\n2\n3\n')
46
38
 
47
39
  const map = await loadTSV(file)
48
40
  assertEquals(map.a, ['1', '2', '3'])
@@ -50,7 +42,7 @@ Deno.test('TSV loading', async (t) => {
50
42
 
51
43
  await t.step('Missing final newline is ignored', async () => {
52
44
  const file = pathToFile('/missing_newline.tsv')
53
- file.opener.stream = () => asyncStreamFromString('a\n1\n2\n3')
45
+ file.opener = new StringOpener('a\n1\n2\n3')
54
46
 
55
47
  const map = await loadTSV(file)
56
48
  assertEquals(map.a, ['1', '2', '3'])
@@ -58,7 +50,7 @@ Deno.test('TSV loading', async (t) => {
58
50
 
59
51
  await t.step('Empty row throws issue', async () => {
60
52
  const file = pathToFile('/empty_row.tsv')
61
- file.opener.stream = () => asyncStreamFromString('a\tb\tc\n1\t2\t3\n\n4\t5\t6\n')
53
+ file.opener = new StringOpener('a\tb\tc\n1\t2\t3\n\n4\t5\t6\n')
62
54
 
63
55
  try {
64
56
  await loadTSV(file)
@@ -69,7 +61,7 @@ Deno.test('TSV loading', async (t) => {
69
61
 
70
62
  await t.step('Mismatched row length throws issue', async () => {
71
63
  const file = pathToFile('/mismatched_row.tsv')
72
- file.opener.stream = () => asyncStreamFromString('a\tb\tc\n1\t2\t3\n4\t5\n')
64
+ file.opener = new StringOpener('a\tb\tc\n1\t2\t3\n4\t5\n')
73
65
 
74
66
  try {
75
67
  await loadTSV(file)
@@ -82,7 +74,7 @@ Deno.test('TSV loading', async (t) => {
82
74
  const file = pathToFile('/long.tsv')
83
75
  // Use 1500 to avoid overlap with default initial capacity
84
76
  const text = 'a\tb\tc\n' + '1\t2\t3\n'.repeat(1500)
85
- file.opener.stream = () => asyncStreamFromString(text)
77
+ file.opener = new StringOpener(text)
86
78
 
87
79
  let map = await loadTSV(file, 0)
88
80
  assertEquals(map.a, [])
@@ -91,21 +83,18 @@ Deno.test('TSV loading', async (t) => {
91
83
 
92
84
  // Do not assume that caching respects maxRows in this test
93
85
  loadTSV.cache.clear()
94
- file.opener.stream = () => asyncStreamFromString(text)
95
86
  map = await loadTSV(file, 1)
96
87
  assertEquals(map.a, ['1'])
97
88
  assertEquals(map.b, ['2'])
98
89
  assertEquals(map.c, ['3'])
99
90
 
100
91
  loadTSV.cache.clear()
101
- file.opener.stream = () => asyncStreamFromString(text)
102
92
  map = await loadTSV(file, 2)
103
93
  assertEquals(map.a, ['1', '1'])
104
94
  assertEquals(map.b, ['2', '2'])
105
95
  assertEquals(map.c, ['3', '3'])
106
96
 
107
97
  loadTSV.cache.clear()
108
- file.opener.stream = () => asyncStreamFromString(text)
109
98
  map = await loadTSV(file, -1)
110
99
  assertEquals(map.a, Array(1500).fill('1'))
111
100
  assertEquals(map.b, Array(1500).fill('2'))
@@ -113,7 +102,7 @@ Deno.test('TSV loading', async (t) => {
113
102
 
114
103
  loadTSV.cache.clear()
115
104
  // Check that maxRows does not truncate shorter files
116
- file.opener.stream = () => asyncStreamFromString('a\tb\tc\n1\t2\t3\n4\t5\t6\n7\t8\t9\n')
105
+ file.opener = new StringOpener('a\tb\tc\n1\t2\t3\n4\t5\t6\n7\t8\t9\n')
117
106
  map = await loadTSV(file, 4)
118
107
  assertEquals(map.a, ['1', '4', '7'])
119
108
  assertEquals(map.b, ['2', '5', '8'])
@@ -125,7 +114,7 @@ Deno.test('TSV loading', async (t) => {
125
114
  const file = pathToFile('/long.tsv')
126
115
  // Use 1500 to avoid overlap with default initial capacity
127
116
  const text = 'a\tb\tc\n' + '1\t2\t3\n'.repeat(1500)
128
- file.opener.stream = () => asyncStreamFromString(text)
117
+ file.opener = new StringOpener(text)
129
118
 
130
119
  let map = await loadTSV(file, 2)
131
120
  assertEquals(map.a, ['1', '1'])
@@ -133,7 +122,6 @@ Deno.test('TSV loading', async (t) => {
133
122
  assertEquals(map.c, ['3', '3'])
134
123
 
135
124
  // Replace stream to ensure cache does not depend on deep object equality
136
- file.opener.stream = () => asyncStreamFromString(text)
137
125
  let repeatMap = await loadTSV(file, 2)
138
126
  assertStrictEquals(map, repeatMap)
139
127
 
@@ -151,21 +139,19 @@ Deno.test('TSV loading', async (t) => {
151
139
  const file = pathToFile('/long.tsv')
152
140
  // Use 1500 to avoid overlap with default initial capacity
153
141
  const text = 'a\tb\tc\n' + '1\t2\t3\n'.repeat(1500)
154
- file.opener.stream = () => asyncStreamFromString(text)
142
+ file.opener = new StringOpener(text)
155
143
 
156
144
  let map = await loadTSV(file, 2)
157
145
  assertEquals(map.a, ['1', '1'])
158
146
  assertEquals(map.b, ['2', '2'])
159
147
  assertEquals(map.c, ['3', '3'])
160
148
 
161
- file.opener.stream = () => asyncStreamFromString(text)
162
149
  let repeatMap = await loadTSV(file, 3)
163
150
  assertNotStrictEquals(map, repeatMap)
164
151
  assertEquals(repeatMap.a, ['1', '1', '1'])
165
152
  assertEquals(repeatMap.b, ['2', '2', '2'])
166
153
  assertEquals(repeatMap.c, ['3', '3', '3'])
167
154
 
168
- file.opener.stream = () => asyncStreamFromString(text)
169
155
  repeatMap = await loadTSV(file, 2)
170
156
  assertStrictEquals(map, repeatMap)
171
157
  assertEquals(repeatMap.a, ['1', '1'])
@@ -175,7 +161,7 @@ Deno.test('TSV loading', async (t) => {
175
161
 
176
162
  await t.step('Raises issue on duplicate header', async () => {
177
163
  const file = pathToFile('/duplicate_header.tsv')
178
- file.opener.stream = () => asyncStreamFromString('a\ta\n1\t2\n')
164
+ file.opener = new StringOpener('a\ta\n1\t2\n')
179
165
 
180
166
  try {
181
167
  await loadTSV(file)
@@ -203,7 +189,7 @@ Deno.test('TSV loading', async (t) => {
203
189
  Deno.test('TSVGZ loading', async (t) => {
204
190
  await t.step('No header and empty file produces empty map', async () => {
205
191
  const file = pathToFile('/empty.tsv.gz')
206
- file.opener.stream = () => compressedStreamFromString('')
192
+ file.opener = new CompressedStringOpener('')
207
193
 
208
194
  const map = await loadTSVGZ(file, [])
209
195
  // map.size looks for a column called map, so work around it
@@ -212,7 +198,7 @@ Deno.test('TSVGZ loading', async (t) => {
212
198
 
213
199
  await t.step('Empty file produces header-only map', async () => {
214
200
  const file = pathToFile('/empty.tsv.gz')
215
- file.opener.stream = () => compressedStreamFromString('')
201
+ file.opener = new CompressedStringOpener('')
216
202
 
217
203
  const map = await loadTSVGZ(file, ['a', 'b', 'c'])
218
204
  assertEquals(map.a, [])
@@ -222,7 +208,7 @@ Deno.test('TSVGZ loading', async (t) => {
222
208
 
223
209
  await t.step('Single column file produces single column maps', async () => {
224
210
  const file = pathToFile('/single_column.tsv')
225
- file.opener.stream = () => compressedStreamFromString('1\n2\n3\n')
211
+ file.opener = new CompressedStringOpener('1\n2\n3\n')
226
212
 
227
213
  const map = await loadTSVGZ(file, ['a'])
228
214
  assertEquals(map.a, ['1', '2', '3'])
@@ -230,7 +216,7 @@ Deno.test('TSVGZ loading', async (t) => {
230
216
 
231
217
  await t.step('Mismatched header length throws issue', async () => {
232
218
  const file = pathToFile('/single_column.tsv.gz')
233
- file.opener.stream = () => compressedStreamFromString('1\n2\n3\n')
219
+ file.opener = new CompressedStringOpener('1\n2\n3\n')
234
220
 
235
221
  try {
236
222
  await loadTSVGZ(file, ['a', 'b'])
@@ -241,7 +227,7 @@ Deno.test('TSVGZ loading', async (t) => {
241
227
 
242
228
  await t.step('Missing final newline is ignored', async () => {
243
229
  const file = pathToFile('/missing_newline.tsv.gz')
244
- file.opener.stream = () => compressedStreamFromString('1\n2\n3')
230
+ file.opener = new CompressedStringOpener('1\n2\n3')
245
231
 
246
232
  const map = await loadTSVGZ(file, ['a'])
247
233
  assertEquals(map.a, ['1', '2', '3'])
@@ -249,7 +235,7 @@ Deno.test('TSVGZ loading', async (t) => {
249
235
 
250
236
  await t.step('Empty row throws issue', async () => {
251
237
  const file = pathToFile('/empty_row.tsv.gz')
252
- file.opener.stream = () => compressedStreamFromString('1\t2\t3\n\n4\t5\t6\n')
238
+ file.opener = new CompressedStringOpener('1\t2\t3\n\n4\t5\t6\n')
253
239
 
254
240
  try {
255
241
  await loadTSVGZ(file, ['a', 'b', 'c'])
@@ -260,7 +246,7 @@ Deno.test('TSVGZ loading', async (t) => {
260
246
 
261
247
  await t.step('Mislabeled TSV throws issue', async () => {
262
248
  const file = pathToFile('/mismatched_row.tsv.gz')
263
- file.opener.stream = () => asyncStreamFromString('a\tb\tc\n1\t2\t3\n4\t5\n')
249
+ file.opener = new StringOpener('a\tb\tc\n1\t2\t3\n4\t5\n')
264
250
 
265
251
  try {
266
252
  await loadTSVGZ(file, ['a', 'b', 'c'])
@@ -274,33 +260,30 @@ Deno.test('TSVGZ loading', async (t) => {
274
260
  // Use 1500 to avoid overlap with default initial capacity
275
261
  const headers = ['a', 'b', 'c']
276
262
  const text = '1\t2\t3\n'.repeat(1500)
277
- file.opener.stream = () => compressedStreamFromString(text)
263
+ file.opener = new CompressedStringOpener(text)
278
264
 
279
265
  let map = await loadTSVGZ(file, headers, 0)
280
266
  assertEquals(map.a, [])
281
267
  assertEquals(map.b, [])
282
268
  assertEquals(map.c, [])
283
269
 
284
- file.opener.stream = () => compressedStreamFromString(text)
285
270
  map = await loadTSVGZ(file, headers, 1)
286
271
  assertEquals(map.a, ['1'])
287
272
  assertEquals(map.b, ['2'])
288
273
  assertEquals(map.c, ['3'])
289
274
 
290
- file.opener.stream = () => compressedStreamFromString(text)
291
275
  map = await loadTSVGZ(file, headers, 2)
292
276
  assertEquals(map.a, ['1', '1'])
293
277
  assertEquals(map.b, ['2', '2'])
294
278
  assertEquals(map.c, ['3', '3'])
295
279
 
296
- file.opener.stream = () => compressedStreamFromString(text)
297
280
  map = await loadTSVGZ(file, headers, -1)
298
281
  assertEquals(map.a, Array(1500).fill('1'))
299
282
  assertEquals(map.b, Array(1500).fill('2'))
300
283
  assertEquals(map.c, Array(1500).fill('3'))
301
284
 
302
285
  // Check that maxRows does not truncate shorter files
303
- file.opener.stream = () => compressedStreamFromString('1\t2\t3\n4\t5\t6\n7\t8\t9\n')
286
+ file.opener = new CompressedStringOpener('1\t2\t3\n4\t5\t6\n7\t8\t9\n')
304
287
  map = await loadTSVGZ(file, headers, 4)
305
288
  assertEquals(map.a, ['1', '4', '7'])
306
289
  assertEquals(map.b, ['2', '5', '8'])
@@ -0,0 +1,32 @@
1
+ import { assertEquals, assertObjectMatch } from '@std/assert'
2
+ import type { BIDSFile, FileTree } from '../types/filetree.ts'
3
+ import { loadSchema } from '../setup/loadSchema.ts'
4
+ import { pathsToTree } from '../files/filetree.test.ts'
5
+ import { nullReadBytes } from '../tests/nullReadBytes.ts'
6
+ import { rootFileTree } from './fixtures.test.ts'
7
+ import { BIDSContext } from './context.ts'
8
+ import { buildAssociations } from './associations.ts'
9
+
10
+ Deno.test('Test association loading', async (t) => {
11
+ const schema = await loadSchema()
12
+ await t.step('Load associations for events.tsv', async () => {
13
+ const eventsFile = rootFileTree.get(
14
+ 'sub-01/ses-01/func/sub-01_ses-01_task-movie_physio.tsv.gz',
15
+ ) as BIDSFile
16
+ const context = new BIDSContext(eventsFile, undefined, rootFileTree)
17
+ context.dataset.schema = schema
18
+ const associations = await buildAssociations(context)
19
+ assertObjectMatch(associations, {
20
+ events: {
21
+ sidecar: {
22
+ StimulusPresentation: {
23
+ ScreenDistance: 1.8,
24
+ ScreenOrigin: ['top', 'left'],
25
+ ScreenResolution: [1920, 1080],
26
+ ScreenSize: [0.472, 0.265],
27
+ },
28
+ },
29
+ },
30
+ })
31
+ })
32
+ })