ata-validator 1.21.0 → 1.22.1

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.
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { levenshtein } = require('./levenshtein');
4
+ const { resolvePointer: walk, UNRESOLVED } = require('./pointer');
4
5
 
5
6
  // Hand-coded format hints. Keep <=60 chars per text.
6
7
  const FORMAT_HINTS = {
@@ -46,8 +47,15 @@ function suggestEnumTypo (received, enumValues) {
46
47
  return null;
47
48
  }
48
49
 
50
+ // The widest container a typo hint is offered on. `suggestEnumTypo` caps its
51
+ // candidate list for the same two reasons: past a certain width the nearest
52
+ // key stops being evidence of a typo, and the scan is a distance computation
53
+ // per key on a value the caller has already rejected.
54
+ const MAX_TYPO_CANDIDATES = 64;
55
+
49
56
  function suggestRequiredTypo (missing, presentKeys) {
50
57
  if (!missing || !Array.isArray(presentKeys)) return null;
58
+ if (presentKeys.length > MAX_TYPO_CANDIDATES) return null;
51
59
  for (const k of presentKeys) {
52
60
  if (typeof k !== 'string') continue;
53
61
  const d = levenshtein(missing, k, 2);
@@ -58,22 +66,14 @@ function suggestRequiredTypo (missing, presentKeys) {
58
66
  return null;
59
67
  }
60
68
 
61
- function suggestFormat (format, received) {
69
+ function suggestFormat (format, raw) {
62
70
  const fn = FORMAT_HINTS[format];
63
71
  if (!fn) return null;
64
- // received is repr-truncated string like '"foo"'; unwrap for testing
65
- let raw = received;
66
- if (typeof raw === 'string' && raw.startsWith('"') && raw.endsWith('"')) {
67
- try { raw = JSON.parse(raw); } catch {}
68
- }
69
72
  const text = fn(raw);
70
73
  return text ? { text, kind: 'format' } : null;
71
74
  }
72
75
 
73
- function suggestCoercion (expectedType, received) {
74
- if (typeof received !== 'string' || !received.startsWith('"') || !received.endsWith('"')) return null;
75
- let raw;
76
- try { raw = JSON.parse(received); } catch { return null; }
76
+ function suggestCoercion (expectedType, raw) {
77
77
  if (typeof raw !== 'string') return null;
78
78
  if (expectedType === 'integer' && /^-?\d+$/.test(raw)) {
79
79
  return { text: 'value would coerce; enable `coerceTypes` or pass an integer', kind: 'coercion' };
@@ -91,26 +91,37 @@ function suggestCoercion (expectedType, received) {
91
91
  * Apply suggestion sources in priority order. Returns the first hit, or null.
92
92
  * @param err Enriched ValidationError (with `received`, `params`, `keyword`)
93
93
  * @param data The full input data (for required-typo)
94
+ * @param at The value at `err.path`, already resolved by the caller, or
95
+ * UNRESOLVED when the caller has none to offer
94
96
  */
95
- function suggestFor (err, data) {
97
+ function suggestFor (err, data, at = UNRESOLVED) {
98
+ // The offending value itself. The caller resolves it once per error and
99
+ // passes it here rather than having each source walk the document again.
100
+ // A caller that passes only an enriched error falls back to un-quoting the
101
+ // repr, which is what every source used to read.
102
+ const raw = at !== UNRESOLVED ? at : parseReceived(err.received);
96
103
  if (err.keyword === 'enum') {
97
- return suggestEnumTypo(parseReceived(err.received), err.params && err.params.allowedValues);
104
+ return suggestEnumTypo(raw, err.params && err.params.allowedValues);
98
105
  }
99
106
  if (err.keyword === 'required') {
100
107
  const missing = err.params && err.params.missingProperty;
101
- let parentPath = err.path || '';
108
+ const path = err.path || '';
109
+ let parentPath = path;
102
110
  if (parentPath.endsWith('/' + missing)) parentPath = parentPath.slice(0, -missing.length - 1);
103
- const parent = walk(data, parentPath);
111
+ // A `required` error usually names the container it failed on, so the
112
+ // value the caller already resolved is the parent. Only the spelling that
113
+ // points at the missing key itself needs a second walk.
114
+ const parent = (parentPath === path && at !== UNRESOLVED) ? at : walk(data, parentPath);
104
115
  if (parent && typeof parent === 'object') {
105
116
  return suggestRequiredTypo(missing, Object.keys(parent));
106
117
  }
107
118
  return null;
108
119
  }
109
120
  if (err.keyword === 'format') {
110
- return suggestFormat(err.params && err.params.format, err.received);
121
+ return suggestFormat(err.params && err.params.format, raw);
111
122
  }
112
123
  if (err.keyword === 'type') {
113
- return suggestCoercion(err.params && err.params.type, err.received);
124
+ return suggestCoercion(err.params && err.params.type, raw);
114
125
  }
115
126
  return null;
116
127
  }
@@ -121,12 +132,4 @@ function parseReceived (r) {
121
132
  return r;
122
133
  }
123
134
 
124
- function walk (data, pointer) {
125
- if (!pointer) return data;
126
- const parts = pointer.replace(/^\//, '').split('/').map(s => s.replace(/~1/g, '/').replace(/~0/g, '~'));
127
- let cur = data;
128
- for (const p of parts) { if (cur == null) return undefined; cur = cur[p]; }
129
- return cur;
130
- }
131
-
132
135
  module.exports = { suggestFor, suggestEnumTypo, suggestRequiredTypo, suggestFormat, suggestCoercion };
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.21.0';
10
+ module.exports = '1.22.1';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ata-validator",
3
- "version": "1.21.0",
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.",
3
+ "version": "1.22.1",
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",
7
7
  "types": "index.d.ts",
@@ -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_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_diagnostic.js && node tests/test_format_engine_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_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_pattern_properties_errors.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_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_data_positions.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_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_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_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_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",
@@ -122,13 +122,13 @@
122
122
  "LICENSE"
123
123
  ],
124
124
  "optionalDependencies": {
125
- "@ata-validator/native-darwin-arm64": "1.21.0",
126
- "@ata-validator/native-darwin-x64": "1.21.0",
127
- "@ata-validator/native-linux-arm64-gnu": "1.21.0",
128
- "@ata-validator/native-linux-arm64-musl": "1.21.0",
129
- "@ata-validator/native-linux-x64-gnu": "1.21.0",
130
- "@ata-validator/native-linux-x64-musl": "1.21.0",
131
- "@ata-validator/native-win32-x64": "1.21.0"
125
+ "@ata-validator/native-darwin-arm64": "1.22.1",
126
+ "@ata-validator/native-darwin-x64": "1.22.1",
127
+ "@ata-validator/native-linux-arm64-gnu": "1.22.1",
128
+ "@ata-validator/native-linux-arm64-musl": "1.22.1",
129
+ "@ata-validator/native-linux-x64-gnu": "1.22.1",
130
+ "@ata-validator/native-linux-x64-musl": "1.22.1",
131
+ "@ata-validator/native-win32-x64": "1.22.1"
132
132
  },
133
133
  "peerDependencies": {
134
134
  "yaml": "^2.0.0"