ata-validator 1.27.1 → 1.29.0

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.
@@ -9,27 +9,22 @@
9
9
  // Self-contained on purpose: `toStandaloneModule({ positions: true })` embeds
10
10
  // this function verbatim via Function.prototype.toString, so it may not close
11
11
  // over anything in this module and may not assume Node globals. The inlined
12
- // escapePtr below duplicates lib/source-positions.js for that reason.
12
+ // pointer escaping below duplicates lib/source-positions.js for that reason.
13
13
  function buildDataPositionMap (input) {
14
- const escapePtr = (s) => s.replace(/~/g, '~0').replace(/\//g, '~1');
15
14
  const text = (typeof Buffer !== 'undefined' && Buffer.isBuffer(input)) ? input.toString('utf8') : String(input);
16
15
  const map = Object.create(null);
17
- const lines = text.split('\n');
18
- const lineStart = new Array(lines.length + 1);
19
- lineStart[0] = 0;
20
- for (let i = 0; i < lines.length; i++) lineStart[i + 1] = lineStart[i] + lines[i].length + 1;
16
+ const n = text.length;
21
17
 
22
- function offsetToLineCol (off) {
23
- let lo = 0, hi = lineStart.length - 1;
24
- while (lo < hi) {
25
- const mid = (lo + hi + 1) >> 1;
26
- if (lineStart[mid] <= off) lo = mid; else hi = mid - 1;
27
- }
28
- return { line: lo + 1, col: off - lineStart[lo] + 1, text: lines[lo] || '' };
29
- }
18
+ // Offsets during the walk, line and column afterwards. Resolving them here
19
+ // cost a binary search and an object allocation for every node in the
20
+ // document, when only the nodes an error names are ever read.
21
+ const ptrs = [];
22
+ const starts = [];
23
+ const lens = [];
24
+ const keyStarts = [];
25
+ const keyLens = [];
30
26
 
31
27
  let i = 0;
32
- const n = text.length;
33
28
 
34
29
  function skipWs () {
35
30
  while (i < n) {
@@ -38,28 +33,40 @@ function buildDataPositionMap (input) {
38
33
  }
39
34
  }
40
35
 
41
- function readString () {
36
+ // Span the string token, leaving `i` just past the closing quote. A plain
37
+ // token is sliced; one holding an escape or a raw control character goes
38
+ // through JSON.parse, which is what decodes `é` and what rejects a
39
+ // literal newline or a bad escape. Values are spanned and not decoded, but a
40
+ // malformed one still has to be rejected, so it is parsed for the throw.
41
+ //
42
+ // A token that does not open with a quote is not simple either. Object keys
43
+ // are read here unconditionally, so a document whose opening quote is missing
44
+ // (`{ mo": 1 }`) arrives with `m` under the cursor, and slicing it would map a
45
+ // key nobody wrote. Parsing the span rejects it instead.
46
+ function readString (decode) {
42
47
  const start = i;
48
+ let simple = text.charCodeAt(i) === 0x22;
43
49
  i++;
50
+ let closed = false;
44
51
  while (i < n) {
45
52
  const ch = text.charCodeAt(i);
46
- if (ch === 0x5c) { i += 2; continue; }
47
- if (ch === 0x22) { i++; return JSON.parse(text.slice(start, i)); }
53
+ if (ch === 0x5c) { simple = false; i += 2; continue; }
54
+ if (ch === 0x22) { i++; closed = true; break; }
55
+ if (ch < 0x20) simple = false;
48
56
  i++;
49
57
  }
50
- throw new Error('unterminated string at offset ' + start);
58
+ if (!closed) throw new Error('unterminated string at offset ' + start);
59
+ if (simple) return decode ? text.slice(start + 1, i - 1) : null;
60
+ const decoded = JSON.parse(text.slice(start, i));
61
+ return decode ? decoded : null;
51
62
  }
52
63
 
53
- function pointerOf (path) {
54
- if (path.length === 0) return '';
55
- return '/' + path.map(escapePtr).join('/');
56
- }
57
-
58
- function walk (path, keySpan) {
64
+ // The pointer is carried down the walk. Rebuilding it per node from a path
65
+ // array cost an array copy, a map and a join for every node.
66
+ function walk (ptr, keyStart, keyLen) {
59
67
  skipWs();
60
68
  if (i >= n) return;
61
69
  const start = i;
62
- const pos = offsetToLineCol(start);
63
70
 
64
71
  const ch = text.charCodeAt(i);
65
72
  if (ch === 0x7b) {
@@ -76,19 +83,16 @@ function buildDataPositionMap (input) {
76
83
  // Record the key token before consuming it. The caret for an error
77
84
  // that names a property belongs on the property, not on the value and
78
85
  // not on the enclosing object.
79
- const keyStart = i;
80
- const keyPos = offsetToLineCol(keyStart);
81
- const key = readString();
82
- const span = {
83
- keyOffset: keyStart,
84
- keyLength: i - keyStart,
85
- keyLine: keyPos.line,
86
- keyCol: keyPos.col,
87
- };
86
+ const memberKeyStart = i;
87
+ const key = readString(true);
88
+ const memberKeyLen = i - memberKeyStart;
88
89
  skipWs();
89
90
  if (text.charCodeAt(i) !== 0x3a) throw new Error('expected ":" at offset ' + i);
90
91
  i++;
91
- walk(path.concat([key]), span);
92
+ const seg = (key.indexOf('~') === -1 && key.indexOf('/') === -1)
93
+ ? key
94
+ : key.replace(/~/g, '~0').replace(/\//g, '~1');
95
+ walk(ptr + '/' + seg, memberKeyStart, memberKeyLen);
92
96
  }
93
97
  } else if (ch === 0x5b) {
94
98
  i++;
@@ -99,7 +103,7 @@ function buildDataPositionMap (input) {
99
103
  if (text.charCodeAt(i) === 0x5d) { i++; break; }
100
104
  if (text.charCodeAt(i) === 0x2c) { i++; continue; }
101
105
  const before = i;
102
- walk(path.concat([String(idx)]));
106
+ walk(ptr + '/' + idx, -1, 0);
103
107
  // A character that begins no value at all, a stray `}` for instance,
104
108
  // leaves the position where it was, and a loop that does not advance
105
109
  // does not end. `validateJSON('[')` hung here on one byte.
@@ -107,7 +111,7 @@ function buildDataPositionMap (input) {
107
111
  idx++;
108
112
  }
109
113
  } else if (ch === 0x22) {
110
- readString();
114
+ readString(false);
111
115
  } else {
112
116
  while (i < n) {
113
117
  const c = text.charCodeAt(i);
@@ -116,19 +120,51 @@ function buildDataPositionMap (input) {
116
120
  }
117
121
  }
118
122
 
119
- const length = i - start;
120
- const entry = { byteOffset: start, length, line: pos.line, col: pos.col, text: pos.text };
121
- if (keySpan) {
122
- entry.keyOffset = keySpan.keyOffset;
123
- entry.keyLength = keySpan.keyLength;
124
- entry.keyLine = keySpan.keyLine;
125
- entry.keyCol = keySpan.keyCol;
126
- }
127
- map[pointerOf(path)] = entry;
123
+ ptrs.push(ptr);
124
+ starts.push(start);
125
+ lens.push(i - start);
126
+ keyStarts.push(keyStart);
127
+ keyLens.push(keyLen);
128
128
  }
129
129
 
130
130
  if (text.charCodeAt(0) === 0xfeff) i = 1;
131
- walk([]);
131
+ walk('', -1, 0);
132
+
133
+ if (ptrs.length === 0) return map;
134
+
135
+ const lines = text.split('\n');
136
+ const lineStart = new Array(lines.length + 1);
137
+ lineStart[0] = 0;
138
+ for (let k = 0; k < lines.length; k++) lineStart[k + 1] = lineStart[k] + lines[k].length + 1;
139
+
140
+ function lineOf (off) {
141
+ let lo = 0, hi = lineStart.length - 1;
142
+ while (lo < hi) {
143
+ const mid = (lo + hi + 1) >> 1;
144
+ if (lineStart[mid] <= off) lo = mid; else hi = mid - 1;
145
+ }
146
+ return lo;
147
+ }
148
+
149
+ for (let k = 0; k < ptrs.length; k++) {
150
+ const off = starts[k];
151
+ const line = lineOf(off);
152
+ const entry = {
153
+ byteOffset: off,
154
+ length: lens[k],
155
+ line: line + 1,
156
+ col: off - lineStart[line] + 1,
157
+ text: lines[line] || '',
158
+ };
159
+ if (keyStarts[k] >= 0) {
160
+ const keyLine = lineOf(keyStarts[k]);
161
+ entry.keyOffset = keyStarts[k];
162
+ entry.keyLength = keyLens[k];
163
+ entry.keyLine = keyLine + 1;
164
+ entry.keyCol = keyStarts[k] - lineStart[keyLine] + 1;
165
+ }
166
+ map[ptrs[k]] = entry;
167
+ }
132
168
  return map;
133
169
  }
134
170
 
package/lib/ts-gen.js CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const ATA_VERSION = require('./version');
4
+
3
5
  // Schema -> TypeScript type declaration.
4
6
  // Emits an interface or type alias for each top-level schema, plus
5
7
  // `isValid` (type predicate) and `validate` signatures.
@@ -215,7 +217,7 @@ function toTypeScript(schema, opts) {
215
217
  ? `${rootDoc}export interface ${rootName} ${rootType}`
216
218
  : `${rootDoc}export type ${rootName} = ${rootType};`;
217
219
 
218
- return `// Auto-generated by ata-validator — do not edit.
220
+ return `// Auto-generated by ata-validator ${ATA_VERSION}, do not edit.
219
221
  ${defLines.length ? defLines.join('\n\n') + '\n\n' : ''}${rootDecl}
220
222
 
221
223
  export interface ValidationError {
@@ -239,7 +241,8 @@ export type Result = ValidResult | InvalidResult;
239
241
  export declare function isValid(data: unknown): data is ${rootName};
240
242
  export declare function validate(data: unknown): Result;
241
243
  export declare const schemaHash: string;
242
- declare const _default: { validate: typeof validate; isValid: typeof isValid; schemaHash: typeof schemaHash };
244
+ export declare const ataVersion: string;
245
+ declare const _default: { validate: typeof validate; isValid: typeof isValid; schemaHash: typeof schemaHash; ataVersion: typeof ataVersion };
243
246
  export default _default;
244
247
  `;
245
248
  }
package/lib/version.js CHANGED
@@ -7,4 +7,4 @@
7
7
  //
8
8
  // Kept in lockstep with package.json by `tests/test_version_sync.js`.
9
9
 
10
- module.exports = '1.27.1';
10
+ module.exports = '1.29.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ata-validator",
3
- "version": "1.27.1",
3
+ "version": "1.29.0",
4
4
  "description": "JSON Schema validation that compiles for speed and still runs where code generation is blocked. Compiled and interpreted engines answer identically at 100% of the official suite. TypeScript inference, Standard Schema V1, and a build step that emits dependency-free modules.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -51,7 +51,7 @@
51
51
  "release:check": "node scripts/regen-safe-regex-source.js && node tests/test_pack_purity.js && node scripts/check-doc-coverage.js && node tests/test_error_codes_lock.js && node tests/test_safe_regex_source_sync.js && node tests/test_version_sync.js",
52
52
  "build": "cmake-js build --target ata",
53
53
  "rebuild": "cmake-js rebuild --target ata",
54
- "test": "node test.js && node tests/test_removed_aot_methods.js && node tests/test_no_native.js && node tests/test_no_eval.js && node tests/test_property_dependencies.js && node tests/test_v1_dialect.js && node tests/test_buffer_path_parity.js && node tests/test_buffer_gate.js && node tests/test_scanner_differential.js && node tests/test_buffer_reject_cost.js && node tests/test_nan_verdict.js && node tests/test_remove_additional_nested.js && node tests/test_exclusive_bounds.js && node tests/test_engine_differential.js && node tests/test_error_shape_differential.js && node tests/test_output_format.js && node tests/test_retry_message.js && node tests/test_describe_schema.js && node tests/test_aot_parse.js && node tests/test_draft7_semantics.js && node tests/test_metaschema_ref.js && node tests/test_pure_js_unsupported.js && node tests/test_native_load_order.js && node tests/test_pack_purity.js && node tests/test_make_native_package.js && node tests/test_browser_nofs.js && node tests/test_browser_imports_guard.js && node tests/test_version_sync.js && node tests/test_native_loaded.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_format_mode.js && node tests/test_aot_additional_props_errors.js && node tests/test_id_anchor_refs.js && node tests/test_engine_routing.js && node tests/test_compile_cache_order.js && node tests/test_engine_diagnostic.js && node tests/test_format_engine_parity.js && node tests/test_uri_helper_parity.js && node tests/test_formats_single_pass.js && node tests/test_format_single_error.js && node tests/test_defs_pointer_alias.js && node tests/test_cross_doc_root_ref.js && node tests/test_codegen_entrypoint_agreement.js && node tests/test_hybrid_agreement.js && node tests/test_codegen_edge_shapes.js && node tests/test_ajv_errors.js && node tests/test_custom_keywords.js && node tests/test_strict_schema.js && node tests/test_aot_external_checks.js && node tests/test_ajv_parity.js && node tests/test_user_format_error_path.js && node tests/test_unevaluated_error_path.js && node tests/test_unevaluated_error_shape.js && node tests/test_pattern_properties_errors.js && node tests/test_additional_properties_scaling.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_error_code_lookup.js && node tests/test_error_order.js && node tests/test_error_order_ordinal.js && node tests/test_rejection_shape.js && node tests/test_lazy_normalization.js && node tests/test_value_equality.js && node tests/test_vocabulary.js && node tests/test_schema_scan.js && node tests/test_lazy_errors.js && node tests/test_lazy_instance.js && node tests/test_cyclic_input.js && node tests/test_native_error_codes.js && node tests/test_verdict_preprocess.js && node tests/test_defaults_own_keys.js && node tests/test_plan_compiler.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_enrich_received.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_malformed_json_termination.js && node tests/test_data_positions.js && node tests/test_file_positions.js && node tests/test_schema_hash.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_additive_fields.js && node tests/test_diagnostic_source.js && node tests/test_diagnose.js && node tests/test_correlate.js && node tests/test_diagnostics_score.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",
54
+ "test": "node test.js && node tests/test_removed_aot_methods.js && node tests/test_no_native.js && node tests/test_no_eval.js && node tests/test_property_dependencies.js && node tests/test_v1_dialect.js && node tests/test_buffer_path_parity.js && node tests/test_buffer_gate.js && node tests/test_scanner_differential.js && node tests/test_buffer_reject_cost.js && node tests/test_nan_verdict.js && node tests/test_remove_additional_nested.js && node tests/test_exclusive_bounds.js && node tests/test_engine_differential.js && node tests/test_error_shape_differential.js && node tests/test_output_format.js && node tests/test_retry_message.js && node tests/test_describe_schema.js && node tests/test_aot_parse.js && node tests/test_draft7_semantics.js && node tests/test_metaschema_ref.js && node tests/test_pure_js_unsupported.js && node tests/test_native_load_order.js && node tests/test_pack_purity.js && node tests/test_make_native_package.js && node tests/test_browser_nofs.js && node tests/test_browser_imports_guard.js && node tests/test_version_sync.js && node tests/test_native_loaded.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_format_mode.js && node tests/test_aot_additional_props_errors.js && node tests/test_id_anchor_refs.js && node tests/test_engine_routing.js && node tests/test_engine_option.js && node tests/test_compile_cache_order.js && node tests/test_engine_diagnostic.js && node tests/test_format_engine_parity.js && node tests/test_uri_helper_parity.js && node tests/test_formats_single_pass.js && node tests/test_format_single_error.js && node tests/test_defs_pointer_alias.js && node tests/test_cross_doc_root_ref.js && node tests/test_codegen_entrypoint_agreement.js && node tests/test_hybrid_agreement.js && node tests/test_codegen_edge_shapes.js && node tests/test_ajv_errors.js && node tests/test_custom_keywords.js && node tests/test_strict_schema.js && node tests/test_aot_external_checks.js && node tests/test_ajv_parity.js && node tests/test_user_format_error_path.js && node tests/test_unevaluated_error_path.js && node tests/test_unevaluated_error_shape.js && node tests/test_pattern_properties_errors.js && node tests/test_additional_properties_scaling.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_error_code_lookup.js && node tests/test_error_order.js && node tests/test_error_order_ordinal.js && node tests/test_rejection_shape.js && node tests/test_lazy_normalization.js && node tests/test_value_equality.js && node tests/test_vocabulary.js && node tests/test_schema_scan.js && node tests/test_lazy_errors.js && node tests/test_lazy_json_errors.js && node tests/test_lazy_instance.js && node tests/test_cyclic_input.js && node tests/test_native_error_codes.js && node tests/test_verdict_preprocess.js && node tests/test_defaults_own_keys.js && node tests/test_plan_compiler.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_enrich_received.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_malformed_json_termination.js && node tests/test_data_positions.js && node tests/test_position_map_cost.js && node tests/test_aot_staleness.js && node tests/test_file_positions.js && node tests/test_schema_hash.js && node tests/test_render_shared.js && node tests/test_renderers.js && node tests/test_additive_fields.js && node tests/test_diagnostic_source.js && node tests/test_diagnose.js && node tests/test_correlate.js && node tests/test_diagnostics_score.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",
55
55
  "bench:size": "node benchmark/bench_aot_size.mjs",
56
56
  "test:suite": "node tests/run_suite.js && node tests/run_suite.js draft7 && node tests/run_suite.js v1",
57
57
  "test:compat": "node tests/test_compat.js",
@@ -118,17 +118,16 @@
118
118
  "t.d.ts",
119
119
  "bin/",
120
120
  "README.md",
121
- "CHANGELOG.md",
122
121
  "LICENSE"
123
122
  ],
124
123
  "optionalDependencies": {
125
- "@ata-validator/native-darwin-arm64": "1.27.1",
126
- "@ata-validator/native-darwin-x64": "1.27.1",
127
- "@ata-validator/native-linux-arm64-gnu": "1.27.1",
128
- "@ata-validator/native-linux-arm64-musl": "1.27.1",
129
- "@ata-validator/native-linux-x64-gnu": "1.27.1",
130
- "@ata-validator/native-linux-x64-musl": "1.27.1",
131
- "@ata-validator/native-win32-x64": "1.27.1"
124
+ "@ata-validator/native-darwin-arm64": "1.29.0",
125
+ "@ata-validator/native-darwin-x64": "1.29.0",
126
+ "@ata-validator/native-linux-arm64-gnu": "1.29.0",
127
+ "@ata-validator/native-linux-arm64-musl": "1.29.0",
128
+ "@ata-validator/native-linux-x64-gnu": "1.29.0",
129
+ "@ata-validator/native-linux-x64-musl": "1.29.0",
130
+ "@ata-validator/native-win32-x64": "1.29.0"
132
131
  },
133
132
  "peerDependencies": {
134
133
  "yaml": "^2.0.0"