Skip to content

Latest commit

 

History

History

README.md

@sourcemeta/blaze

NPM Version NPM Downloads GitHub contributors

A pure JavaScript port of the evaluator from Blaze, a high-performance C++ JSON Schema validator. Zero dependencies. Supports Draft 4, Draft 6, Draft 7, 2019-09, and 2020-12 with schema-specific code generation for near-native speed.

Install

npm install --save @sourcemeta/blaze

Usage

Blaze evaluates pre-compiled schema templates. Compile your JSON Schema using the JSON Schema CLI (see the compile command):

npm install --global @sourcemeta/jsonschema

cat > schema.json <<'EOF'
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "integer" }
  },
  "required": [ "name" ]
}
EOF

jsonschema compile schema.json --fast > template.json

Then validate instances:

import { readFileSync } from "node:fs";
import { Blaze } from "@sourcemeta/blaze";

const template =
  JSON.parse(readFileSync("template.json", "utf-8"));
const evaluator = new Blaze(template);

// true or false
console.log(evaluator.validate({ name: "John", age: 30 }));

With an evaluation callback for tracing:

const instance = { name: "John", age: 30 };
const result = evaluator.validate(instance,
  (type, valid, instruction,
   evaluatePath, instanceLocation, annotation) => {
    console.log(type, evaluatePath,
      instanceLocation, valid);
  });
console.log(result); // true or false

Parsing large integers

JavaScript's JSON.parse silently truncates integers that exceed Number.MAX_SAFE_INTEGER to IEEE 754 double-precision floats. If your schemas or instances contain large integers, pass Blaze.reviver to JSON.parse to preserve them as BigInt values. This relies on the JSON.parse source text access proposal (Stage 4, shipped in all major engines):

const template =
  JSON.parse(readFileSync("template.json", "utf-8"), Blaze.reviver);
const evaluator = new Blaze(template);

const instance =
  JSON.parse(readFileSync("instance.json", "utf-8"), Blaze.reviver);
console.log(evaluator.validate(instance));

The evaluator handles BigInt values natively in all numeric instructions. Without a reviver, large integers are silently truncated and validation may produce incorrect results for affected values.

Why compile separately?

Unlike validators that compile and evaluate in a single step, Blaze separates the two. You compile your schemas ahead of time using the JSON Schema CLI (jsonschema compile schema.json) on CI or at build time.

The compilation step analyses the schema, resolves all references, and produces a set of optimised low-level instructions serialised as JSON that every evaluator can rely on. This evaluator package then executes those instructions against your data, with no knowledge of JSON Schema itself.

  • Consistent validation across languages. The same compiled schema produces identical results whether evaluated in JavaScript, Python, Java, or C++ (we are working hard increase the number of ports) so you never have to rely on multiple implementations with different interpretations of the standard

  • No schema processing at startup. The evaluator loads pre-compiled instructions. There is no reference resolution, or vocabulary processing at runtime

  • Schema governance. Compiled schemas can be managed, versioned, and distributed centrally via Sourcemeta One, ensuring all consumers validate against the same compiled artifact

Limitations

No arbitrary-precision real number support. Large integers can be preserved as BigInt using a reviver (see above), but JavaScript has no equivalent type for arbitrary-precision real numbers. JSON.parse truncates values like 0.1000000000000000000000000000000001 to IEEE 754 doubles, and there is no reviver-based workaround:

$ node --eval "console.log(JSON.parse('0.1000000000000000000000000000000001'))"
0.1

Numeric keywords like multipleOf that depend on exact decimal arithmetic may produce incorrect results for real values that lose precision during parsing. The TC39 Decimal proposal (Stage 2) aims to address this in the future.