Skip to content

compileSchema lets the fallback draft override an explicit $schema #115

Description

@MicroMilo

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:

{"selected":"draft-07"}

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:

{"selected":"draft-07"}

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.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions