ata-validator 0.13.0 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/index.js +25 -11
- package/lib/aot-build.js +5 -1
- package/lib/js-compiler.js +11 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to ata-validator are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/), and this project adheres to semantic versioning.
|
|
4
4
|
|
|
5
|
+
## 0.13.2 — 2026-05-09
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Invalid validation crashed in environments without the native addon** (Cloudflare Workers, browsers, Bun without N-API). When the JS error-codegen probe couldn't produce a safe error function, `errFn` fell through to `this._compiled.validate(d)`. With no native addon `_compiled` stays `null`, so the call threw `TypeError: Cannot read properties of null (reading 'validate')`. Valid inputs were unaffected because they short-circuited before reaching `errFn`. The fallback now stays on a JS-only path when `native` isn't present, returning the boolean result with a generic detail-not-available error so callers see `{ valid: false, errors: [...] }` instead of a crash. Added `tests/test_no_native.js` (Workers-style sandbox) to lock the behavior. Fixes #22.
|
|
10
|
+
|
|
11
|
+
## 0.13.1 — 2026-05-09
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Custom format checkers in `validate()`** are now actually applied. The combined codegen path (used by `Validator#validate` and one-shot `validate()`) silently dropped the `userFormats` argument, so schemas with `format: <user-defined>` returned `{ valid: true }` regardless of the checker function's return value. The boolean (`isValidObject`) and error-only paths were already wired correctly. Fixes RJSF integration where custom formats are routed through `customFormats` (rjsf-team/react-jsonschema-form#5052).
|
|
16
|
+
- **Glob patterns with backslash separators on Windows** now resolve correctly in `ata build`. The Node 18 fallback regex only recognized forward slashes, so `path.join(dir, '*.json')` produced patterns the matcher couldn't parse on `windows-latest` runners.
|
|
17
|
+
|
|
5
18
|
## 0.13.0 — 2026-05-09
|
|
6
19
|
|
|
7
20
|
### Added
|
package/index.js
CHANGED
|
@@ -566,23 +566,37 @@ class Validator {
|
|
|
566
566
|
safeErrFn = (d) => jsErrFn(d, true);
|
|
567
567
|
} catch {}
|
|
568
568
|
}
|
|
569
|
-
// errFn: use JS codegen if safe, else
|
|
570
|
-
//
|
|
569
|
+
// errFn: use JS codegen if safe, else native fallback (only when native
|
|
570
|
+
// is available). Environments without the native addon — Cloudflare
|
|
571
|
+
// Workers, browser, Bun without N-API — get a JS-only fallback so the
|
|
572
|
+
// invalid path doesn't dereference a null _compiled.
|
|
571
573
|
const hasUnevaluated = schemaObj && (schemaObj.unevaluatedProperties !== undefined || schemaObj.unevaluatedItems !== undefined || this._schemaStr.includes('unevaluatedProperties') || this._schemaStr.includes('unevaluatedItems'))
|
|
572
574
|
const hasDynRef = this._schemaStr.includes('"$dynamicRef"') || this._schemaStr.includes('"$dynamicAnchor"')
|
|
575
|
+
const jsOnlyFallback = (d) => ({
|
|
576
|
+
valid: jsFn(d),
|
|
577
|
+
errors: jsFn(d) ? [] : [{
|
|
578
|
+
keyword: 'validation',
|
|
579
|
+
instancePath: '',
|
|
580
|
+
schemaPath: '',
|
|
581
|
+
params: {},
|
|
582
|
+
message: 'schema validation failed (detailed errors unavailable without native addon)'
|
|
583
|
+
}]
|
|
584
|
+
});
|
|
573
585
|
const errFn =
|
|
574
586
|
safeErrFn ||
|
|
575
587
|
(hasUnevaluated
|
|
576
588
|
? (d) => ({ valid: jsFn(d), errors: jsFn(d) ? [] : [{ code: 'unevaluated', path: '', message: 'unevaluated property or item' }] })
|
|
577
|
-
:
|
|
578
|
-
?
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
589
|
+
: !native
|
|
590
|
+
? jsOnlyFallback
|
|
591
|
+
: hasDynRef
|
|
592
|
+
? (d) => {
|
|
593
|
+
this._ensureNative();
|
|
594
|
+
return this._compiled.validateJSON(JSON.stringify(d));
|
|
595
|
+
}
|
|
596
|
+
: (d) => {
|
|
597
|
+
this._ensureNative();
|
|
598
|
+
return this._compiled.validate(d);
|
|
599
|
+
});
|
|
586
600
|
|
|
587
601
|
// Best path: combined validator (single pass, validates + collects errors)
|
|
588
602
|
// Valid data: returns VALID_RESULT, no allocation
|
package/lib/aot-build.js
CHANGED
|
@@ -8,7 +8,11 @@ const { Validator } = require('..');
|
|
|
8
8
|
|
|
9
9
|
async function expandGlobs(globs) {
|
|
10
10
|
const out = [];
|
|
11
|
-
for (const
|
|
11
|
+
for (const raw of globs) {
|
|
12
|
+
// Glob patterns use forward slashes; normalize Windows backslashes so the
|
|
13
|
+
// matcher (Node 22+ fs.glob or the fallback regex) sees a consistent
|
|
14
|
+
// separator. Node accepts forward slashes in paths on Windows.
|
|
15
|
+
const g = raw.replace(/\\/g, '/');
|
|
12
16
|
if (typeof fs.promises.glob === 'function') {
|
|
13
17
|
// Node 22+
|
|
14
18
|
for await (const f of fs.promises.glob(g)) out.push(path.resolve(f));
|
package/lib/js-compiler.js
CHANGED
|
@@ -3001,7 +3001,7 @@ function genCodeE(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
3001
3001
|
// Returns VALID_RESULT for valid data, {valid:false, errors} for invalid.
|
|
3002
3002
|
// Avoids double-pass (jsFn → false → errFn runs same checks again).
|
|
3003
3003
|
// Uses type-aware optimizations: after type check passes, skip guards.
|
|
3004
|
-
function compileToJSCombined(schema, VALID_RESULT, schemaMap) {
|
|
3004
|
+
function compileToJSCombined(schema, VALID_RESULT, schemaMap, userFormats) {
|
|
3005
3005
|
// Bail on unevaluated keywords — combined codegen doesn't support them yet
|
|
3006
3006
|
if (typeof schema === 'object' && schema !== null) {
|
|
3007
3007
|
const s = JSON.stringify(schema)
|
|
@@ -3063,7 +3063,7 @@ function compileToJSCombined(schema, VALID_RESULT, schemaMap) {
|
|
|
3063
3063
|
}
|
|
3064
3064
|
|
|
3065
3065
|
const ctx = { varCounter: 0, helperCode: [], closureVars: ['_cpLen'], closureVals: [_cpLen],
|
|
3066
|
-
rootDefs: cRootDefs, refStack: new Set(), schemaMap: schemaMap || null, anchors: cAnchors, rootSchema: schema }
|
|
3066
|
+
rootDefs: cRootDefs, refStack: new Set(), schemaMap: schemaMap || null, anchors: cAnchors, rootSchema: schema, userFormats: userFormats || null }
|
|
3067
3067
|
const lines = []
|
|
3068
3068
|
genCodeC(schema, 'd', '', lines, ctx, '#')
|
|
3069
3069
|
if (lines.length === 0) return () => VALID_RESULT
|
|
@@ -3321,6 +3321,15 @@ function genCodeC(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
3321
3321
|
if (fc) {
|
|
3322
3322
|
const code = fc(v, isStr).replace(/return false/g, `{${fail('format', 'format', `{format:'${esc(schema.format)}'}`, `'must match format "${esc(schema.format)}"'`)}}`)
|
|
3323
3323
|
lines.push(code)
|
|
3324
|
+
} else if (ctx.userFormats && typeof ctx.userFormats[schema.format] === 'function') {
|
|
3325
|
+
const safeName = schema.format.replace(/[^a-zA-Z0-9_]/g, '_')
|
|
3326
|
+
const closureName = `_uf_${safeName}`
|
|
3327
|
+
if (!ctx.closureVars.includes(closureName)) {
|
|
3328
|
+
ctx.closureVars.push(closureName)
|
|
3329
|
+
ctx.closureVals.push(ctx.userFormats[schema.format])
|
|
3330
|
+
}
|
|
3331
|
+
const guard = isStr ? '' : `typeof ${v}==='string'&&`
|
|
3332
|
+
lines.push(`if(${guard}!${closureName}(${v})){${fail('format', 'format', `{format:'${esc(schema.format)}'}`, `'must match format "${esc(schema.format)}"'`)}}`)
|
|
3324
3333
|
}
|
|
3325
3334
|
}
|
|
3326
3335
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"description": "Ultra-fast JSON Schema validator. 5x faster validation, 159,000x faster compilation. Works without native addon. Cross-schema $ref, Draft 2020-12 + Draft 7, V8-optimized JS codegen, simdjson, RE2, multi-core. Standard Schema V1 compatible.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"rebuild": "cmake-js rebuild --target ata",
|
|
41
41
|
"prebuild": "pkg-prebuilds-copy --baseDir build/Release --source ata.node --name=ata --strip --napi_version=10",
|
|
42
42
|
"prebuild-all": "npm run prebuild -- --arch x64 && npm run prebuild -- --arch arm64",
|
|
43
|
-
"test": "node test.js && node tests/test_aot_build.js && node tests/test_aot_differential.js && node tests/test_aot_cli_build.js && node tests/test_aot_cli_smoke.js",
|
|
43
|
+
"test": "node test.js && node tests/test_no_native.js && node tests/test_aot_build.js && node tests/test_aot_differential.js && node tests/test_aot_cli_build.js && node tests/test_aot_cli_smoke.js",
|
|
44
44
|
"test:suite": "node tests/run_suite.js",
|
|
45
45
|
"test:compat": "node tests/test_compat.js",
|
|
46
46
|
"test:standard-schema": "node tests/test_standard_schema.js",
|