Skip to content

fromJsonSchemaDocument silently ignores not, if/then/else, dependencies, and contains #7410

Description

@filipfalcon

What version of Effect is running?

4.0.0-rc.111

What steps can reproduce the bug?

The importer walks a fixed list of recognised keywords, and anything outside it is never read. Four draft-07 validation keywords fall outside that list, so a document using them imports cleanly and then validates less than it declares, with no error or warning.

import { JsonSchema, Schema, SchemaRepresentation } from "effect"

const accepts = (document, value) => {
  const schema = SchemaRepresentation.fromJsonSchemaDocument(JsonSchema.fromSchemaDraft07(document))
  return Schema.decodeUnknownResult(schema)(value)._tag === "Success"
}

// Every pair below is a document and a value that document rejects.
console.log("not         ", accepts(
  { type: "object", properties: { a: { not: { type: "string" } } } },
  { a: "x" }))

console.log("if/then/else", accepts(
  { type: "object",
    properties: { beta: { type: "boolean" }, kind: { type: "string" } },
    if: { properties: { beta: { const: true } }, required: ["beta"] },
    then: {},
    else: { properties: { kind: { enum: ["a", "b"] } } } },
  { kind: "zzz" }))

console.log("dependencies", accepts(
  { type: "object", properties: { a: {}, b: {} }, dependencies: { a: ["b"] } },
  { a: 1 }))

console.log("contains    ", accepts(
  { type: "object", properties: { xs: { type: "array", contains: { const: 7 } } } },
  { xs: [1, 2] }))

What is the expected behavior?

Each of the four values is invalid against the document paired with it, so each should decode to a Failure.

If these keywords are out of scope for the importer, it should say so at import time rather than drop them, in the same way patterns already requires an explicit opt-in to weakened validation. Silently returning a schema that is weaker than the document it was built from gives no way to tell the difference between "validated" and "partly validated".

What do you see instead?

All four are accepted. The import emits nothing, so the resulting schema looks like a faithful translation of the document:

not          true
if/then/else true
dependencies true
contains     true

Additional information

The keywords the importer reads are enumerated in internal/schema/fromJsonSchemaDocument.tsjsonSchemaObjectKeys, jsonSchemaArrayKeys, jsonSchemaStringKeys, jsonSchemaNumberKeys, plus explicit handling for allOf, anyOf, oneOf, $ref, enum and const. There is no branch for an unrecognised keyword, so one is simply not visited.

I checked the neighbours: oneOf exclusivity, propertyNames, uniqueItems, minItems, multipleOf, const, enum, required and additionalProperties are all honored. This looks like four gaps in one list rather than a broad problem.

A unsupported: "error" | "ignore" option defaulting to "error" would resolve it without implementing the keywords, and would match the existing patterns behaviour.

Related but distinct: #7409 concerns a reference the importer does read and resolves to the wrong node. This one is about keywords it never reads.

Both surfaced importing SchemaStore's dependabot-2.0.json, where the dropped conditionals silently remove the package-ecosystem enum and schedule being required.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions