ata-validator 1.0.0 → 1.0.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 +14 -0
- package/include/ata.h +5 -5
- package/index.js +51 -16
- package/lib/js-compiler.js +5 -0
- package/lib/version.js +1 -1
- package/package.json +2 -2
- package/prebuilds/ata-darwin-arm64/node-napi-v10.node +0 -0
- package/prebuilds/ata-linux-arm64/node-napi-v10.node +0 -0
- package/prebuilds/ata-linux-arm64-musl/node-napi-v10.node +0 -0
- package/prebuilds/ata-linux-x64/node-napi-v10.node +0 -0
- package/prebuilds/ata-linux-x64-musl/node-napi-v10.node +0 -0
- package/prebuilds/ata-win32-x64/node-napi-v10.node +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
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
|
+
## 1.0.2 - 2026-07-17
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Cross-schema `$ref` pointers into `#/definitions/...` resolved to nothing after draft-07 normalization renamed the target to `$defs`, and the generated validator silently accepted invalid data. The pointer walk now treats `definitions` and `$defs` as aliases.
|
|
10
|
+
- Schemas passed by the caller (the `schemas` option, `addSchema()`, and the root schema) were normalized in place, mutating objects the caller still owns. Anyone reusing those objects afterwards, such as Fastify handing the same shared schema to its serializer, saw corrupted keys. Normalization now works on a copy; caller objects are never touched.
|
|
11
|
+
- The new copy preserves symbol-keyed markers, so `t.refine` refinements survive normalization and `validateAsync` keeps enforcing them.
|
|
12
|
+
|
|
13
|
+
## 1.0.1 - 2026-07-16
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- `version()` reported 0.10.4 on platforms with a native prebuild: the `ATA_VERSION` constant in `include/ata.h` had not been bumped since 0.10.4 and the native answer takes precedence over `lib/version.js`. The header now carries the real version and the version-sync test checks it, so it cannot drift again.
|
|
18
|
+
|
|
5
19
|
## 1.0.0 - 2026-07-15
|
|
6
20
|
|
|
7
21
|
1.0 is a stability commitment, not a feature release. The API surface, the error result shape, and the error code registry are now covered by the semver guarantees in [docs/STABILITY.md](docs/STABILITY.md).
|
package/include/ata.h
CHANGED
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
#include <variant>
|
|
9
9
|
#include <vector>
|
|
10
10
|
|
|
11
|
-
#define ATA_VERSION "0.
|
|
11
|
+
#define ATA_VERSION "1.0.2"
|
|
12
12
|
|
|
13
13
|
namespace ata {
|
|
14
14
|
|
|
15
|
-
inline constexpr uint32_t VERSION_MAJOR =
|
|
16
|
-
inline constexpr uint32_t VERSION_MINOR =
|
|
17
|
-
inline constexpr uint32_t VERSION_REVISION =
|
|
15
|
+
inline constexpr uint32_t VERSION_MAJOR = 1;
|
|
16
|
+
inline constexpr uint32_t VERSION_MINOR = 0;
|
|
17
|
+
inline constexpr uint32_t VERSION_REVISION = 2;
|
|
18
18
|
|
|
19
19
|
inline constexpr std::string_view version() noexcept {
|
|
20
|
-
return
|
|
20
|
+
return ATA_VERSION;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
enum class error_code : uint8_t {
|
package/index.js
CHANGED
|
@@ -344,22 +344,57 @@ function createPaddedBuffer(jsonStr) {
|
|
|
344
344
|
return { buffer: padded, length: jsonBuf.length };
|
|
345
345
|
}
|
|
346
346
|
|
|
347
|
+
// Deep-clone a value, copying own symbol keys by reference at every level.
|
|
348
|
+
// Arrays and plain objects are cloned recursively; primitives, RegExp,
|
|
349
|
+
// functions, and other non-plain values are returned as-is. Symbol values
|
|
350
|
+
// (e.g. refinement lists, OPTIONAL markers) are owned by the caller's builder
|
|
351
|
+
// and sharing them is correct — they are never mutated by normalization.
|
|
352
|
+
function _deepCloneWithSymbols(v) {
|
|
353
|
+
if (v === null || typeof v !== 'object') return v;
|
|
354
|
+
if (Array.isArray(v)) {
|
|
355
|
+
const a = new Array(v.length);
|
|
356
|
+
for (let i = 0; i < v.length; i++) a[i] = _deepCloneWithSymbols(v[i]);
|
|
357
|
+
return a;
|
|
358
|
+
}
|
|
359
|
+
// Only clone plain objects (skip RegExp, Date, etc.).
|
|
360
|
+
if (Object.getPrototypeOf(v) !== Object.prototype && Object.getPrototypeOf(v) !== null) return v;
|
|
361
|
+
const out = Object.create(null);
|
|
362
|
+
for (const k of Object.keys(v)) Object.defineProperty(out, k, { value: _deepCloneWithSymbols(v[k]), writable: true, enumerable: true, configurable: true });
|
|
363
|
+
for (const sym of Object.getOwnPropertySymbols(v)) out[sym] = v[sym];
|
|
364
|
+
return Object.setPrototypeOf(out, Object.prototype);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Normalize a caller-provided schema without mutating the original.
|
|
368
|
+
// Clones only when normalization would change the object (draft-07 keys
|
|
369
|
+
// present or nullable fields present). Internal-only — not exported.
|
|
370
|
+
function _normalizeCallerSchema(s) {
|
|
371
|
+
const needsDraft7 = s && s.$schema && (
|
|
372
|
+
s.$schema === 'http://json-schema.org/draft-07/schema#' ||
|
|
373
|
+
s.$schema === 'http://json-schema.org/draft-07/schema'
|
|
374
|
+
)
|
|
375
|
+
const str = JSON.stringify(s)
|
|
376
|
+
const copy = _deepCloneWithSymbols(s)
|
|
377
|
+
if (needsDraft7) normalizeDraft7(copy)
|
|
378
|
+
normalizeNullable(copy)
|
|
379
|
+
// Return original when normalization produced no change, copy otherwise.
|
|
380
|
+
// Change-detection uses JSON content only; symbols do not affect it.
|
|
381
|
+
return JSON.stringify(copy) === str ? s : copy
|
|
382
|
+
}
|
|
383
|
+
|
|
347
384
|
function buildSchemaMap(schemas) {
|
|
348
385
|
if (!schemas) return null
|
|
349
386
|
const map = new Map()
|
|
350
387
|
if (Array.isArray(schemas)) {
|
|
351
388
|
for (const s of schemas) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
const id = s.$id
|
|
389
|
+
const normalized = _normalizeCallerSchema(s)
|
|
390
|
+
const id = normalized.$id
|
|
355
391
|
if (!id) throw new Error('Schema in schemas option must have $id')
|
|
356
|
-
map.set(id,
|
|
392
|
+
map.set(id, normalized)
|
|
357
393
|
}
|
|
358
394
|
} else {
|
|
359
395
|
for (const [key, s] of Object.entries(schemas)) {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
map.set(s.$id || key, s)
|
|
396
|
+
const normalized = _normalizeCallerSchema(s)
|
|
397
|
+
map.set(normalized.$id || key, normalized)
|
|
363
398
|
}
|
|
364
399
|
}
|
|
365
400
|
return map
|
|
@@ -449,7 +484,6 @@ function resolveSchemaForPreprocess(schema, schemaMap) {
|
|
|
449
484
|
class Validator {
|
|
450
485
|
constructor(schema, opts) {
|
|
451
486
|
const options = opts || {};
|
|
452
|
-
const schemaObj = typeof schema === "string" ? JSON.parse(schema) : schema;
|
|
453
487
|
|
|
454
488
|
// Ultra-fast path: same schema object reference -> return cached instance
|
|
455
489
|
// JS constructor returning an object makes `new` return that object
|
|
@@ -459,10 +493,12 @@ class Validator {
|
|
|
459
493
|
if (hit) return hit;
|
|
460
494
|
}
|
|
461
495
|
|
|
462
|
-
//
|
|
463
|
-
|
|
464
|
-
//
|
|
465
|
-
|
|
496
|
+
// When schema is a string, JSON.parse already produces a fresh object.
|
|
497
|
+
// When schema is an object, normalization runs on a clone so the caller's
|
|
498
|
+
// object is never touched.
|
|
499
|
+
const schemaObj = typeof schema === "string"
|
|
500
|
+
? JSON.parse(schema)
|
|
501
|
+
: _normalizeCallerSchema(schema);
|
|
466
502
|
|
|
467
503
|
this._schemaStr = null; // lazy: computed on first use
|
|
468
504
|
this._schemaObj = schemaObj;
|
|
@@ -1132,10 +1168,9 @@ class Validator {
|
|
|
1132
1168
|
if (!schema || !schema.$id) {
|
|
1133
1169
|
throw new Error('Schema must have $id')
|
|
1134
1170
|
}
|
|
1135
|
-
//
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
this._schemaMap.set(schema.$id, schema)
|
|
1171
|
+
// Normalize a copy so the caller's object is never mutated.
|
|
1172
|
+
const normalized = _normalizeCallerSchema(schema)
|
|
1173
|
+
this._schemaMap.set(normalized.$id, normalized)
|
|
1139
1174
|
}
|
|
1140
1175
|
|
|
1141
1176
|
_ensureCodegen() {
|
package/lib/js-compiler.js
CHANGED
|
@@ -549,6 +549,11 @@ function walkJsonPointer(root, fragment) {
|
|
|
549
549
|
let target = root
|
|
550
550
|
for (const p of parts) {
|
|
551
551
|
if (target == null || typeof target !== 'object') return null
|
|
552
|
+
if (!(p in target)) {
|
|
553
|
+
const alt = p === 'definitions' ? '$defs' : p === '$defs' ? 'definitions' : null
|
|
554
|
+
if (alt !== null && alt in target) { target = target[alt]; continue }
|
|
555
|
+
return null
|
|
556
|
+
}
|
|
552
557
|
target = target[p]
|
|
553
558
|
}
|
|
554
559
|
return target == null ? null : target
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
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",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"rebuild": "cmake-js rebuild --target ata",
|
|
49
49
|
"prebuild": "pkg-prebuilds-copy --baseDir build/Release --source ata.node --name=ata --strip --napi_version=10",
|
|
50
50
|
"prebuild-all": "npm run prebuild -- --arch x64 && npm run prebuild -- --arch arm64",
|
|
51
|
-
"test": "node test.js && node tests/test_removed_aot_methods.js && node tests/test_no_native.js && node tests/test_browser_nofs.js && node tests/test_browser_imports_guard.js && node tests/test_version_sync.js && node tests/test_safe_regex_source_sync.js && node tests/test_t_builder.js && node tests/test_async_refine.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_id_anchor_refs.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_error_messages.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",
|
|
51
|
+
"test": "node test.js && node tests/test_removed_aot_methods.js && node tests/test_no_native.js && node tests/test_browser_nofs.js && node tests/test_browser_imports_guard.js && node tests/test_version_sync.js && node tests/test_safe_regex_source_sync.js && node tests/test_t_builder.js && node tests/test_async_refine.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_id_anchor_refs.js && node tests/test_defs_pointer_alias.js && node tests/test_no_input_mutation.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_error_messages.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",
|
|
52
52
|
"bench:size": "node benchmark/bench_aot_size.mjs",
|
|
53
53
|
"test:suite": "node tests/run_suite.js",
|
|
54
54
|
"test:compat": "node tests/test_compat.js",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|