diff --git a/bids-validator/src/issues/list.ts b/bids-validator/src/issues/list.ts index 8af740533..aeaf8dbd3 100644 --- a/bids-validator/src/issues/list.ts +++ b/bids-validator/src/issues/list.ts @@ -36,11 +36,19 @@ export const filenameIssues: IssueDefinitionRecord = { }, JSON_KEY_REQUIRED: { severity: 'error', - reason: "A data file's JSON sidecar is missing a key listed as required.", + reason: 'A JSON flle is missing a key listed as required.', }, JSON_KEY_RECOMMENDED: { severity: 'warning', - reason: 'A data files JSON sidecar is missing a key listed as recommended.', + reason: 'A JSON file is missing a key listed as recommended.', + }, + SIDECAR_KEY_REQUIRED: { + severity: 'error', + reason: "A data file's JSON sidecar is missing a key listed as required.", + }, + SIDECAR_KEY_RECOMMENDED: { + severity: 'warning', + reason: "A data file's JSON sidecar is missing a key listed as recommended.", }, JSON_SCHEMA_VALIDATION_ERROR: { severity: 'error', diff --git a/bids-validator/src/schema/applyRules.ts b/bids-validator/src/schema/applyRules.ts index 6c8e9083a..6c5e0bdd9 100644 --- a/bids-validator/src/schema/applyRules.ts +++ b/bids-validator/src/schema/applyRules.ts @@ -418,12 +418,18 @@ function evalJsonCheck( schema: GenericSchema, schemaPath: string, ): void { + const sidecarRule = schemaPath.match(/rules\.sidecar/) + // Sidecar rules apply specifically to data files, as JSON files cannot have sidecars + // Count on other JSON rules to use selectors to match the correct files + if (context.extension === '.json' && sidecarRule) return + + const json = sidecarRule ? context.sidecar : context.json for (const [key, requirement] of Object.entries(rule.fields)) { const severity = getFieldSeverity(requirement, context) // @ts-expect-error const metadataDef = schema.objects.metadata[key] const keyName: string = metadataDef.name - if (severity && severity !== 'ignore' && !(keyName in context.sidecar)) { + if (severity && severity !== 'ignore' && !(keyName in json)) { if (requirement.issue?.code && requirement.issue?.message) { context.issues.add({ key: requirement.issue.code, @@ -432,19 +438,25 @@ function evalJsonCheck( files: [{ ...context.file }], }) } else if (severity === 'error') { - context.issues.addNonSchemaIssue('JSON_KEY_REQUIRED', [ - { - ...context.file, - evidence: `missing ${keyName} as per ${schemaPath}`, - }, - ]) + context.issues.addNonSchemaIssue( + sidecarRule ? 'SIDECAR_KEY_REQUIRED' : 'JSON_KEY_REQUIRED', + [ + { + ...context.file, + evidence: `missing ${keyName} as per ${schemaPath}`, + }, + ], + ) } else if (severity === 'warning') { - context.issues.addNonSchemaIssue('JSON_KEY_RECOMMENDED', [ - { - ...context.file, - evidence: `missing ${keyName} as per ${schemaPath}`, - }, - ]) + context.issues.addNonSchemaIssue( + sidecarRule ? 'SIDECAR_KEY_RECOMMENDED' : 'JSON_KEY_RECOMMENDED', + [ + { + ...context.file, + evidence: `missing ${keyName} as per ${schemaPath}`, + }, + ], + ) } } diff --git a/bids-validator/src/schema/context.ts b/bids-validator/src/schema/context.ts index 11691265d..6ec139032 100644 --- a/bids-validator/src/schema/context.ts +++ b/bids-validator/src/schema/context.ts @@ -134,6 +134,9 @@ export class BIDSContext implements Context { * Earlier (deeper) sidecars take precedence over later ones. */ async loadSidecar() { + if (this.extension === '.json') { + return + } const sidecars = walkBack(this.file) for (const file of sidecars) { const json = await file