@@ -3,17 +3,21 @@ import type { Schema as MetaSchema } from '@bids/schema/metaschema'
33
44import type { BIDSFile } from '../types/filetree.ts'
55import type { BIDSContext } from './context.ts'
6+ import { loadJSON } from '../files/json.ts'
67import { loadTSV } from '../files/tsv.ts'
78import { parseBvalBvec } from '../files/dwi.ts'
89import { readSidecars , walkBack } from '../files/inheritance.ts'
910import { evalCheck } from './applyRules.ts'
1011import { expressionFunctions } from './expressionLanguage.ts'
12+ import { readEntities } from './entities.ts'
1113
1214import { readText } from '../files/access.ts'
1315
1416interface WithSidecar {
1517 sidecar : Record < string , unknown >
1618}
19+ type LoadFunction = ( file : BIDSFile , options : any ) => Promise < any >
20+ type MultiLoadFunction = ( files : BIDSFile [ ] , options : any ) => Promise < any >
1721
1822function defaultAssociation ( file : BIDSFile , _options : any ) : Promise < { path : string } > {
1923 return Promise . resolve ( { path : file . path } )
@@ -33,7 +37,7 @@ async function constructSidecar(file: BIDSFile): Promise<Record<string, unknown>
3337 *
3438 * Many associations only consist of a path; this object is for more complex associations.
3539 */
36- const associationLookup = {
40+ const associationLookup : Record < string , LoadFunction > = {
3741 events : async ( file : BIDSFile , options : { maxRows : number } ) : Promise < Events & WithSidecar > => {
3842 const columns = await loadTSV ( file , options . maxRows )
3943 . catch ( ( e ) => {
@@ -103,6 +107,24 @@ const associationLookup = {
103107 }
104108 } ,
105109}
110+ const multiAssociationLookup : Record < string , MultiLoadFunction > = {
111+ coordsystems : async (
112+ files : BIDSFile [ ] ,
113+ options : any ,
114+ ) : Promise < { paths : string [ ] ; spaces : string [ ] ; ParentCoordinateSystems : string [ ] } > => {
115+ const jsons = await Promise . allSettled (
116+ files . map ( ( f ) => loadJSON ( f ) . catch ( ( ) => ( { } as Record < string , unknown > ) ) ) ,
117+ )
118+ const parents = jsons . map ( ( j ) =>
119+ j . status === 'fulfilled' ? j . value ?. ParentCoordinateSystem : undefined
120+ ) . filter ( ( p ) => p ) as string [ ]
121+ return {
122+ paths : files . map ( ( f ) => f . path ) ,
123+ spaces : files . map ( ( f ) => readEntities ( f . name ) . entities ?. space ) ,
124+ ParentCoordinateSystems : parents ,
125+ }
126+ } ,
127+ }
106128
107129export async function buildAssociations (
108130 context : BIDSContext ,
@@ -134,33 +156,37 @@ export async function buildAssociations(
134156 rule . target . suffix ,
135157 rule . target ?. entities ?? [ ] ,
136158 ) . next ( ) . value
137- if ( Array . isArray ( file ) ) {
138- file = file [ 0 ]
139- }
140- } catch ( error ) {
141- if (
142- error && typeof error === 'object' && 'code' in error &&
143- error . code === 'MULTIPLE_INHERITABLE_FILES'
144- ) {
145- // @ts -expect-error
159+ } catch ( error : any ) {
160+ if ( error ?. code === 'MULTIPLE_INHERITABLE_FILES' ) {
146161 context . dataset . issues . add ( error )
147- break
162+ continue
148163 } else {
149164 throw error
150165 }
151166 }
152167
153- if ( file ) {
154- // @ts -expect-error
155- const load = associationLookup [ key ] ?? defaultAssociation
156- // @ts -expect-error
157- associations [ key ] = await load ( file , { maxRows : context . dataset . options ?. maxRows } ) . catch (
158- ( error : any ) => {
159- if ( error . code ) {
160- context . dataset . issues . add ( { ...error , location : file . path } )
161- }
162- } ,
163- )
168+ if ( file && ! ( Array . isArray ( file ) && file . length === 0 ) ) {
169+ const options = { maxRows : context . dataset . options ?. maxRows }
170+ if ( key in multiAssociationLookup ) {
171+ const load = multiAssociationLookup [ key ]
172+ if ( ! Array . isArray ( file ) ) {
173+ file = [ file ]
174+ }
175+ associations [ key as keyof Associations ] = await load ( file , options ) . catch ( ( e : any ) => { } )
176+ } else {
177+ const load = associationLookup [ key ] ?? defaultAssociation
178+ if ( Array . isArray ( file ) ) {
179+ file = file [ 0 ]
180+ }
181+ const location = file . path
182+ associations [ key as keyof Associations ] = await load ( file , options ) . catch (
183+ ( error : any ) => {
184+ if ( error . code ) {
185+ context . dataset . issues . add ( { ...error , location } )
186+ }
187+ } ,
188+ )
189+ }
164190 }
165191 }
166192 return Promise . resolve ( associations )
0 commit comments