ata-validator 0.17.3 → 0.17.4
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 +8 -0
- package/bin/ata.js +5 -0
- package/index.js +27 -2
- package/lib/js-compiler.js +15 -3
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
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.17.4 - 2026-05-25
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Standalone output now embeds user-supplied format functions. `toStandaloneModule` and `bundleCompact` referenced the `_uf_<name>` format helpers without declaring them, so the generated module threw `_uf_<name> is not defined` on the first validation, and their error path skipped the custom format entirely (so `validate` disagreed with `isValid`). Both now serialize the format functions via `Function#toString` and run them on the error path too, matching `bundleStandalone`.
|
|
10
|
+
- Compiled validators report per-property errors for schema-valued `additionalProperties`. The AOT error path previously emitted a single generic `validation failed`; it now validates each undeclared property against the subschema and reports the precise `/<key>` error, matching the runtime validator.
|
|
11
|
+
- `ata --version` (and `-V`) prints the CLI version instead of failing with `unknown command`.
|
|
12
|
+
|
|
5
13
|
## 0.17.3 - 2026-05-25
|
|
6
14
|
|
|
7
15
|
### Security
|
package/bin/ata.js
CHANGED
|
@@ -45,6 +45,7 @@ Build options:
|
|
|
45
45
|
--dual Emit both .compiled.mjs (with source) and .compiled.min.mjs (without)
|
|
46
46
|
|
|
47
47
|
-h, --help Show this message
|
|
48
|
+
-V, --version Print the ata-validator version
|
|
48
49
|
|
|
49
50
|
Examples:
|
|
50
51
|
ata compile schemas/user.json -o src/generated/user.validator.mjs
|
|
@@ -386,6 +387,10 @@ function main() {
|
|
|
386
387
|
|
|
387
388
|
const cmd = argv[0];
|
|
388
389
|
if (cmd === '-h' || cmd === '--help' || cmd === 'help') { usage(); return; }
|
|
390
|
+
if (cmd === '-V' || cmd === '--version' || cmd === 'version') {
|
|
391
|
+
process.stdout.write(require('../package.json').version + '\n');
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
389
394
|
|
|
390
395
|
const rest = argv.slice(1);
|
|
391
396
|
let args;
|
package/index.js
CHANGED
|
@@ -1214,7 +1214,7 @@ module.exports = { boolFn, hybridFactory, errFn };
|
|
|
1214
1214
|
jsErrFn = compileToJSCodegenWithErrors(
|
|
1215
1215
|
typeof this._schemaObj === 'object' ? this._schemaObj : {},
|
|
1216
1216
|
null,
|
|
1217
|
-
|
|
1217
|
+
this._userFormats,
|
|
1218
1218
|
(source && sourceMap && schemaFile) ? { sourceMap, schemaFile } : null,
|
|
1219
1219
|
);
|
|
1220
1220
|
const errSrc = jsErrFn && jsErrFn._errSource ? jsErrFn._errSource : '';
|
|
@@ -1266,6 +1266,16 @@ module.exports = { boolFn, hybridFactory, errFn };
|
|
|
1266
1266
|
// them at module scope too, or _fn references undefined names (e.g. _af1_b0).
|
|
1267
1267
|
const preambleDecls = jsFn._preambleSource ? jsFn._preambleSource + '\n' : '';
|
|
1268
1268
|
|
|
1269
|
+
// User-supplied format functions are referenced as _uf_<name> by both the
|
|
1270
|
+
// boolean (_fn) and error (errFn) bodies. Embed them via Function#toString
|
|
1271
|
+
// so the standalone module stays self-contained.
|
|
1272
|
+
let formatDecls = '';
|
|
1273
|
+
if (jsFn._formatClosures && jsFn._formatClosures.length > 0) {
|
|
1274
|
+
formatDecls = jsFn._formatClosures
|
|
1275
|
+
.map(({ name, fn }) => `const ${name} = ${fn.toString()};`)
|
|
1276
|
+
.join('\n') + '\n';
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1269
1279
|
const validBody = errCore
|
|
1270
1280
|
? 'return _fn(data) ? VALID : { valid: false, errors: errFn(data, true).errors }'
|
|
1271
1281
|
: 'return _fn(data) ? VALID : ABORT';
|
|
@@ -1288,7 +1298,7 @@ const ABORT = Object.freeze({
|
|
|
1288
1298
|
path: '',
|
|
1289
1299
|
})]),
|
|
1290
1300
|
});
|
|
1291
|
-
${closureDecls}${preambleDecls}const _fn = function(d) {
|
|
1301
|
+
${closureDecls}${preambleDecls}${formatDecls}const _fn = function(d) {
|
|
1292
1302
|
${src}
|
|
1293
1303
|
};
|
|
1294
1304
|
${errCore}function isValid(data) { return _fn(data); }
|
|
@@ -1575,6 +1585,7 @@ Validator.bundleCompact = function (schemas, opts) {
|
|
|
1575
1585
|
const jsErrFn = compileToJSCodegenWithErrors(
|
|
1576
1586
|
typeof schema === "string" ? JSON.parse(schema) : schema,
|
|
1577
1587
|
v._schemaMap,
|
|
1588
|
+
v._userFormats,
|
|
1578
1589
|
);
|
|
1579
1590
|
if (jsFn._usesSafeRe || (jsErrFn && jsErrFn._usesSafeRe)) bundleUsesSafeRe = true;
|
|
1580
1591
|
// Hoisted anyOf/oneOf branch helpers (e.g. `_af1_b0`) must travel with the
|
|
@@ -1586,6 +1597,7 @@ Validator.bundleCompact = function (schemas, opts) {
|
|
|
1586
1597
|
return {
|
|
1587
1598
|
hybrid,
|
|
1588
1599
|
err: jsErrFn && jsErrFn._errSource ? jsErrFn._errSource : null,
|
|
1600
|
+
fmt: jsFn._formatClosures || null,
|
|
1589
1601
|
};
|
|
1590
1602
|
});
|
|
1591
1603
|
|
|
@@ -1624,6 +1636,19 @@ Validator.bundleCompact = function (schemas, opts) {
|
|
|
1624
1636
|
const declKW = isEsm ? "const" : "var";
|
|
1625
1637
|
out += `${declKW} R=Object.freeze({valid:true,errors:Object.freeze([])});\n`;
|
|
1626
1638
|
|
|
1639
|
+
// User format functions are referenced as _uf_<name> by the hybrid and error
|
|
1640
|
+
// bodies. Collect them across all schemas (deduped by name) and embed via
|
|
1641
|
+
// Function#toString so the bundle stays self-contained.
|
|
1642
|
+
const fmtSeen = new Set();
|
|
1643
|
+
for (const e of entries) {
|
|
1644
|
+
if (!e || !e.fmt) continue;
|
|
1645
|
+
for (const { name, fn } of e.fmt) {
|
|
1646
|
+
if (fmtSeen.has(name)) continue;
|
|
1647
|
+
fmtSeen.add(name);
|
|
1648
|
+
out += `${declKW} ${name}=${fn.toString()};\n`;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1627
1652
|
// Shared hybrid factories
|
|
1628
1653
|
out += `${declKW} H=[\n`;
|
|
1629
1654
|
out += bodies
|
package/lib/js-compiler.js
CHANGED
|
@@ -2558,9 +2558,6 @@ function compileToJSCodegenWithErrors(schema, schemaMap, userFormats, sourceOpts
|
|
|
2558
2558
|
if (s.includes('unevaluatedProperties') || s.includes('unevaluatedItems')) return null
|
|
2559
2559
|
// Bail on self-referencing schemas — error codegen doesn't support recursion
|
|
2560
2560
|
if (s.includes('"$ref":"#"')) return null
|
|
2561
|
-
// Bail on additionalProperties as a schema — genCodeE does not emit the
|
|
2562
|
-
// per-key sub-schema loop. Let the closure path handle detailed errors.
|
|
2563
|
-
if (hasAdditionalPropertiesSchema(schema)) return null
|
|
2564
2561
|
}
|
|
2565
2562
|
if (typeof schema === 'boolean') {
|
|
2566
2563
|
return schema
|
|
@@ -3012,6 +3009,21 @@ function genCodeE(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
3012
3009
|
}
|
|
3013
3010
|
}
|
|
3014
3011
|
|
|
3012
|
+
// additionalProperties as a schema — validate each property not declared in
|
|
3013
|
+
// `properties` against the subschema, with a dynamic /<key> path. codegenSafe
|
|
3014
|
+
// guarantees no patternProperties or composition here, so "additional" is
|
|
3015
|
+
// simply "not declared".
|
|
3016
|
+
if (typeof schema.additionalProperties === 'object' && schema.additionalProperties !== null) {
|
|
3017
|
+
const ki = ctx.varCounter++
|
|
3018
|
+
const known = Object.keys(schema.properties || {})
|
|
3019
|
+
const guard = known.length ? `const _ak${ki}=new Set([${known.map((k) => JSON.stringify(k)).join(',')}]);` : ''
|
|
3020
|
+
const keep = known.length ? `if(!_ak${ki}.has(_k${ki})){` : `{`
|
|
3021
|
+
lines.push(`if(typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v})){${guard}for(const _k${ki} in ${v}){${keep}`)
|
|
3022
|
+
const p = pathExpr ? `${pathExpr}+'/'+_k${ki}` : `'/'+_k${ki}`
|
|
3023
|
+
genCodeE(schema.additionalProperties, `${v}[_k${ki}]`, p, lines, ctx, schemaPrefix + '/additionalProperties')
|
|
3024
|
+
lines.push(`}}}`)
|
|
3025
|
+
}
|
|
3026
|
+
|
|
3015
3027
|
// dependentSchemas
|
|
3016
3028
|
if (schema.dependentSchemas) {
|
|
3017
3029
|
for (const [key, depSchema] of Object.entries(schema.dependentSchemas)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.4",
|
|
4
4
|
"description": "JSON Schema validation with first-class TypeScript and zero runtime cost. AOT compile to per-schema ESM modules with zero validator dependency. Generic Validator<T> for TypeBox/Zod/Valibot composition. Optional runtime API. Standard Schema V1 compatible.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"rebuild": "cmake-js rebuild --target ata",
|
|
43
43
|
"prebuild": "pkg-prebuilds-copy --baseDir build/Release --source ata.node --name=ata --strip --napi_version=10",
|
|
44
44
|
"prebuild-all": "npm run prebuild -- --arch x64 && npm run prebuild -- --arch arm64",
|
|
45
|
-
"test": "node test.js && node tests/test_no_native.js && node tests/test_safe_regex.js && node tests/test_safe_regex_integration.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 && node tests/test_bundle_standalone.js && node tests/test_standalone_anyof.js && node tests/test_typed_validator_runner.js && node tests/test_define_schema.js && node tests/test_error_codes_lock.js && node tests/test_nullable.js && node tests/test_validate_and_parse.js && node tests/test_validate_data.js && node tests/test_enrich_error.js && node tests/test_rich_errors_optout.js && node tests/test_source_positions.js && node tests/fuzz_positions.js && node tests/test_data_positions.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_runtime_error_dx.js && node tests/test_aot_error_dx.js && node tests/test_abort_early.js && node tests/test_branch_collapse.js && node tests/test_suggestions.js && node tests/test_cli_validate.js && node benchmark/bench_aot_size.mjs",
|
|
45
|
+
"test": "node test.js && node tests/test_no_native.js && node tests/test_safe_regex.js && node tests/test_safe_regex_integration.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 && node tests/test_bundle_standalone.js && node tests/test_standalone_anyof.js && node tests/test_standalone_formats.js && node tests/test_aot_additional_props_errors.js && node tests/test_typed_validator_runner.js && node tests/test_define_schema.js && node tests/test_error_codes_lock.js && node tests/test_nullable.js && node tests/test_validate_and_parse.js && node tests/test_validate_data.js && node tests/test_enrich_error.js && node tests/test_rich_errors_optout.js && node tests/test_source_positions.js && node tests/fuzz_positions.js && node tests/test_data_positions.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_runtime_error_dx.js && node tests/test_aot_error_dx.js && node tests/test_abort_early.js && node tests/test_branch_collapse.js && node tests/test_suggestions.js && node tests/test_cli_validate.js && node tests/test_cli_version.js && node benchmark/bench_aot_size.mjs",
|
|
46
46
|
"bench:size": "node benchmark/bench_aot_size.mjs",
|
|
47
47
|
"test:suite": "node tests/run_suite.js",
|
|
48
48
|
"test:compat": "node tests/test_compat.js",
|