Summary
compileSchema documents options.draft as a fallback used only when the schema does not define $schema. The implementation currently evaluates options.draft ?? schema.$schema, so a provided fallback draft overrides an explicit schema dialect. A schema declaring draft-04 can therefore be compiled as draft-07 when options.draft is draft-07.
Code path
Relevant current main anchors, checked at commit 1cc2a3045f615ef67104f02449c6fd58afebeb6a:
src/compileSchema.ts:43-60 documents draft as a fallback when no $schema is defined, including the combined example that should use draft-04.
src/compileSchema.test.ts:63-71 has a test named should prefer $schema over draft options, but its assertion is truthiness-style and does not catch the wrong version.
src/compileSchema.ts:113-115 selects the draft with options.draft ?? schema.$schema.
Steps to reproduce
Run against current main after the existing dist/jlib.js build artifact is present:
node -e "const fs=require('fs'),vm=require('vm'); vm.runInThisContext(fs.readFileSync('dist/jlib.js','utf8')); const node=jlib.compileSchema({'\$schema':'http://json-schema.org/draft-04/schema#'},{draft:'http://json-schema.org/draft-07/schema#',drafts:[jlib.draft04,jlib.draft07,jlib.draft2020]}); console.log(JSON.stringify({selected:node.getDraftVersion()}))"
Actual output:
Neighboring control: when the schema has no $schema, options.draft correctly acts as the fallback.
node -e "const fs=require('fs'),vm=require('vm'); vm.runInThisContext(fs.readFileSync('dist/jlib.js','utf8')); const node=jlib.compileSchema({},{draft:'http://json-schema.org/draft-07/schema#',drafts:[jlib.draft04,jlib.draft07,jlib.draft2020]}); console.log(JSON.stringify({selected:node.getDraftVersion()}))"
Control output:
Expected behavior
When a schema has an explicit $schema that matches an available draft, that dialect should take precedence. options.draft should be used only as the documented fallback when $schema is absent.
Actual behavior
options.draft is evaluated first, so the fallback suppresses the schema's explicit $schema. This can change keyword interpretation and validation semantics for schemas that deliberately declare a dialect.
Existing coverage
I checked the current issue and PR lists for related compileSchema, draft, and $schema precedence items. I found draft-related issues and PRs, but did not find one covering this fallback-precedence bug.
Suggested fix
Give schema.$schema precedence over options.draft in compileSchema, e.g. select schema.$schema ?? options.draft for JSON schemas. Also update the existing precedence test to assert equality instead of truthiness.
Suggested tests
- Assert that
compileSchema({ $schema: draft04 }, { draft: draft07, drafts: [...] }).getDraftVersion() equals draft-04.
- Keep the fallback-only case where
compileSchema({}, { draft: draft07, drafts: [...] }) returns draft-07.
Submitted with Codex.
Summary
compileSchemadocumentsoptions.draftas a fallback used only when the schema does not define$schema. The implementation currently evaluatesoptions.draft ?? schema.$schema, so a provided fallback draft overrides an explicit schema dialect. A schema declaring draft-04 can therefore be compiled as draft-07 whenoptions.draftis draft-07.Code path
Relevant current
mainanchors, checked at commit1cc2a3045f615ef67104f02449c6fd58afebeb6a:src/compileSchema.ts:43-60documentsdraftas a fallback when no$schemais defined, including the combined example that should use draft-04.src/compileSchema.test.ts:63-71has a test namedshould prefer $schema over draft options, but its assertion is truthiness-style and does not catch the wrong version.src/compileSchema.ts:113-115selects the draft withoptions.draft ?? schema.$schema.Steps to reproduce
Run against current
mainafter the existingdist/jlib.jsbuild artifact is present:node -e "const fs=require('fs'),vm=require('vm'); vm.runInThisContext(fs.readFileSync('dist/jlib.js','utf8')); const node=jlib.compileSchema({'\$schema':'http://json-schema.org/draft-04/schema#'},{draft:'http://json-schema.org/draft-07/schema#',drafts:[jlib.draft04,jlib.draft07,jlib.draft2020]}); console.log(JSON.stringify({selected:node.getDraftVersion()}))"Actual output:
{"selected":"draft-07"}Neighboring control: when the schema has no
$schema,options.draftcorrectly acts as the fallback.node -e "const fs=require('fs'),vm=require('vm'); vm.runInThisContext(fs.readFileSync('dist/jlib.js','utf8')); const node=jlib.compileSchema({},{draft:'http://json-schema.org/draft-07/schema#',drafts:[jlib.draft04,jlib.draft07,jlib.draft2020]}); console.log(JSON.stringify({selected:node.getDraftVersion()}))"Control output:
{"selected":"draft-07"}Expected behavior
When a schema has an explicit
$schemathat matches an available draft, that dialect should take precedence.options.draftshould be used only as the documented fallback when$schemais absent.Actual behavior
options.draftis evaluated first, so the fallback suppresses the schema's explicit$schema. This can change keyword interpretation and validation semantics for schemas that deliberately declare a dialect.Existing coverage
I checked the current issue and PR lists for related
compileSchema, draft, and$schemaprecedence items. I found draft-related issues and PRs, but did not find one covering this fallback-precedence bug.Suggested fix
Give
schema.$schemaprecedence overoptions.draftincompileSchema, e.g. selectschema.$schema ?? options.draftfor JSON schemas. Also update the existing precedence test to assert equality instead of truthiness.Suggested tests
compileSchema({ $schema: draft04 }, { draft: draft07, drafts: [...] }).getDraftVersion()equalsdraft-04.compileSchema({}, { draft: draft07, drafts: [...] })returnsdraft-07.Submitted with Codex.