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.
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/PKG-INFO +1 -1
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/deno.json +1 -1
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/pyproject.toml +1 -1
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/deno.ts +1 -1
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/filetree.test.ts +2 -9
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/inheritance.ts +18 -0
- bids_validator_deno-2.2.1/src/files/openers.test.ts +154 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/tsv.test.ts +21 -38
- bids_validator_deno-2.2.1/src/schema/associations.test.ts +32 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/associations.ts +68 -31
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/context.test.ts +16 -4
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/context.ts +11 -20
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/expressionLanguage.test.ts +3 -2
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/fixtures.test.ts +27 -2
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/walk.ts +19 -4
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/hed-integration.test.ts +4 -5
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/regression.test.ts +3 -3
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/utils.ts +0 -6
- bids_validator_deno-2.2.1/src/utils/queue.ts +43 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/bids.ts +1 -6
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameIdentify.test.ts +9 -9
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameValidate.test.ts +3 -3
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/validateFiles.test.ts +8 -4
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/LICENSE +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/README.md +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/pdm_build.py +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/.git-meta.json +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/bids-validator.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/access.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/access.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/browser.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/browser.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/deno.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/dwi.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/dwi.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/filetree.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/gzip.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/gzip.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/ignore.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/ignore.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/inheritance.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/json.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/json.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/nifti.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/nifti.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/openers.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/repo.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/streams.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/streams.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/tiff.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/tiff.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/files/tsv.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/issues/datasetIssues.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/issues/datasetIssues.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/issues/list.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/issues/list.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/main.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/applyRules.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/applyRules.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/datatypes.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/datatypes.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/entities.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/entities.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/expressionLanguage.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/tables.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/tables.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/schema/walk.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/setup/loadSchema.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/setup/loadSchema.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/setup/options.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/setup/options.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/setup/requestPermissions.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/summary/collectSubjectMetadata.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/summary/summary.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/summary/summary.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/README.md +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/bom-utf16.tsv +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/bom-utf8.json +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/generate-filenames.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/bids_examples.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/common.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/derivatives.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/empty_files.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/nifti_rules.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/valid_dataset.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/valid_filenames.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/local/valid_headers.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/nullReadBytes.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/schema-expression-language.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/tests/simple-dataset.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/check.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/columns.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/columns.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/filetree.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/issues.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/schema.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/types/validation-result.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/errors.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/logger.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/logger.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/memoize.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/objectPathHandler.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/utils/output.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/bids.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/citation.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/citation.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameCase.test.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameCase.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameIdentify.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/filenameValidate.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/hed.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/internal/emptyFile.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/internal/unusedFile.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/validators/json.ts +0 -0
- {bids_validator_deno-2.2.0 → bids_validator_deno-2.2.1}/src/version.ts +0 -0
|
@@ -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 {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
+
})
|