Skip to content

Commit f61b385

Browse files
committed
feat: Retrieve datatype and modality from BIDSFile and schema
1 parent 8daf24f commit f61b385

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

src/schema/datatypes.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { assert, assertObjectMatch } from '@std/assert'
2+
import { loadSchema } from '../setup/loadSchema.ts'
3+
import { BIDSContext, BIDSContextDataset } from '../schema/context.ts'
4+
import { pathsToTree } from '../files/filetree.ts'
5+
import type { BIDSFile } from '../types/filetree.ts'
6+
7+
import { findDatatype, modalityTable } from './datatypes.ts'
8+
9+
const schema = await loadSchema()
10+
11+
// Creates a file object as part of a minimal file tree
12+
const makeFile = (path: string): BIDSFile => pathsToTree([path]).get(path) as BIDSFile
13+
14+
Deno.test('test modalityTable', async (t) => {
15+
await t.step('empty schema', () => {
16+
assertObjectMatch(modalityTable({}), {})
17+
})
18+
19+
await t.step('real schema', async () => {
20+
const table = modalityTable(schema)
21+
// Memoization check
22+
assert(modalityTable(schema) == table)
23+
// spot check
24+
assertObjectMatch(table, {
25+
'anat': 'mri',
26+
'perf': 'mri',
27+
'eeg': 'eeg',
28+
})
29+
})
30+
})
31+
32+
Deno.test('test findDatatype', async (t) => {
33+
await t.step('root files', async () => {
34+
const path = makeFile('/participants.tsv')
35+
assertObjectMatch(findDatatype(path, schema), { datatype: '', modality: '' })
36+
})
37+
await t.step('non-datatype parent', async () => {
38+
const path = makeFile('/stimuli/image.png')
39+
assertObjectMatch(findDatatype(path, schema), { datatype: '', modality: '' })
40+
})
41+
await t.step('phenotype file', async () => {
42+
const path = makeFile('/phenotype/survey.tsv')
43+
assertObjectMatch(findDatatype(path, schema), { datatype: 'phenotype', modality: '' })
44+
})
45+
await t.step('data files', async () => {
46+
for (
47+
const [filename, datatype, modality] of [
48+
['/sub-01/anat/sub-01_T1w.nii.gz', 'anat', 'mri'],
49+
['/sub-01/eeg/sub-01_task-rest_eeg.edf', 'eeg', 'eeg'],
50+
['/sub-01/perf/sub-01_task-rest_bold.nii.gz', 'perf', 'mri'],
51+
]
52+
) {
53+
const path = makeFile(filename)
54+
assertObjectMatch(findDatatype(path, schema), { datatype, modality })
55+
}
56+
})
57+
})

src/schema/datatypes.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import type { BIDSFile } from '../types/filetree.ts'
2+
import type { Schema } from '../types/schema.ts'
3+
import { memoize } from '../utils/memoize.ts'
4+
5+
function _modalityTable(schema: Schema): Record<string, string> {
6+
const modalities: Record<string, string> = {}
7+
const rules = (schema.rules?.modalities ?? {}) as Record<string, { datatypes: string[] }>
8+
for (const [modality, { datatypes }] of Object.entries(rules)) {
9+
for (const datatype of datatypes) {
10+
modalities[datatype] = modality
11+
}
12+
}
13+
return modalities
14+
}
15+
16+
// Construct once per schema; should only be multiple in tests
17+
export const modalityTable = memoize(_modalityTable)
18+
19+
export function findDatatype(
20+
file: BIDSFile,
21+
schema: Schema,
22+
): { datatype: string; modality: string } {
23+
const lookup = modalityTable(schema)
24+
const datatype = file.parent?.name
25+
if (!schema?.objects?.datatypes[datatype]) {
26+
return { datatype: '', modality: '' }
27+
}
28+
const modality = lookup[datatype] ?? ''
29+
return { datatype, modality }
30+
}

0 commit comments

Comments
 (0)