ata-validator 1.32.0 → 1.32.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.
@@ -918,8 +918,15 @@ const PROTO_NAMES = new Set([...Object.getOwnPropertyNames(Object.prototype), '_
918
918
  // and reading the errors of a product document went from 3.9 to 5.8 us. The
919
919
  // helper only runs once `in` has said yes, and on an ordinary object it
920
920
  // answers from the prototype without looking at the key.
921
- const OWN_HELPERS = 'const _hop=Object.prototype.hasOwnProperty;function _h(o,k){return _hop.call(o,k)}' +
922
- 'function _ok(o,k){return o.__proto__===Object.prototype||_hop.call(o,k)}' +
921
+ //
922
+ // `__proto__` is read through the accessor on Object.prototype, which Deno
923
+ // removes. There every read came back undefined, every object took the per-key
924
+ // hasOwnProperty path, and a ten-field check went from 2.5 to 40 ns. Where the
925
+ // accessor is missing the prototype comes from Object.getPrototypeOf instead,
926
+ // chosen by a constant the engine folds, so Node pays nothing for the branch.
927
+ const OWN_HELPERS = 'const _PN=({}).__proto__===Object.prototype;' +
928
+ 'const _hop=Object.prototype.hasOwnProperty;function _h(o,k){return _hop.call(o,k)}' +
929
+ 'function _ok(o,k){return (_PN?o.__proto__:Object.getPrototypeOf(o))===Object.prototype||_hop.call(o,k)}' +
923
930
  'function _hall(o,ks){for(let i=0;i<ks.length;i++)if(!_hop.call(o,ks[i]))return false;return true}'
924
931
  //
925
932
  // Better still, the prototype is read once per object: a node that asks about
@@ -928,6 +935,11 @@ const OWN_HELPERS = 'const _hop=Object.prototype.hasOwnProperty;function _h(o,k)
928
935
  // helper reading `__proto__` for each key was megamorphic, since it saw every
929
936
  // object shape in the document, and cost the error path about a microsecond
930
937
  // on a product document.
938
+ // Whether `v`, already known to be an object, has Object.prototype as its
939
+ // prototype, read without depending on the __proto__ accessor. Needs OWN_HELPERS.
940
+ function protoIs (v) {
941
+ return `((_PN?${v}.__proto__:Object.getPrototypeOf(${v}))===Object.prototype)`
942
+ }
931
943
  function ownKeyExpr (ctx, v, key) {
932
944
  hoistOnce(ctx, '_ownHoisted', OWN_HELPERS)
933
945
  const k = JSON.stringify(key)
@@ -957,7 +969,8 @@ function withPlain (schema, v, lines, ctx, run) {
957
969
  if (!ctx.plainOf) ctx.plainOf = new Map()
958
970
  const name = '_pk' + ctx.varCounter++
959
971
  const at = lines.length
960
- lines.push(`const ${name}=typeof ${v}==='object'&&${v}!==null&&${v}.__proto__===Object.prototype`)
972
+ const decl = `const ${name}=typeof ${v}==='object'&&${v}!==null&&${protoIs(v)}`
973
+ lines.push(decl)
961
974
  const prev = ctx.plainOf.get(v)
962
975
  ctx.plainOf.set(v, name)
963
976
  try {
@@ -970,14 +983,15 @@ function withPlain (schema, v, lines, ctx, run) {
970
983
  const re = new RegExp('\\b' + name + '\\b')
971
984
  let used = false
972
985
  for (let i = at + 1; i < lines.length && !used; i++) if (re.test(lines[i])) used = true
973
- if (!used && lines[at] === `const ${name}=typeof ${v}==='object'&&${v}!==null&&${v}.__proto__===Object.prototype`) lines.splice(at, 1)
986
+ if (!used && lines[at] === decl) lines.splice(at, 1)
974
987
  }
975
988
  }
976
989
  // The same test at run time, for the closure compiler.
977
990
  const _hop = Object.prototype.hasOwnProperty
991
+ const _PN = ({}).__proto__ === Object.prototype
978
992
  function hasOwnKey (d, key) {
979
993
  if (PROTO_NAMES.has(key)) return _hop.call(d, key)
980
- return key in d && (d.__proto__ === Object.prototype || _hop.call(d, key))
994
+ return key in d && ((_PN ? d.__proto__ : Object.getPrototypeOf(d)) === Object.prototype || _hop.call(d, key))
981
995
  }
982
996
 
983
997
  const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'toString', 'valueOf',
@@ -2270,7 +2284,7 @@ function genCodeNode(schema, v, lines, ctx, knownType) {
2270
2284
  // Read directly: the object type is already established here, and a
2271
2285
  // flag declared for this alone costs more than it saves. The list is
2272
2286
  // built only on that path, which an ordinary object never takes.
2273
- lines.push(`if(${v}.__proto__!==Object.prototype&&!_hall(${v},${JSON.stringify(typed)}))return false`)
2287
+ lines.push(`if(!${protoIs(v)}&&!_hall(${v},${JSON.stringify(typed)}))return false`)
2274
2288
  }
2275
2289
  } else if (schema.required && schema.required.length > 0) {
2276
2290
  const checks = schema.required.map(key => `!${ownKeyExpr(ctx, v, key)}`)
@@ -4906,6 +4920,21 @@ function genCodeCNode(schema, v, pathExpr, lines, ctx, schemaPrefix) {
4906
4920
  const allowed = propKeys.map(k => JSON.stringify(k)).join(',')
4907
4921
  body = `const _a${ci}=new Set([${allowed}]);let _x${ci}=0;for(const _f${ci} in ${v}){if(!_a${ci}.has(_f${ci})){_x${ci}=1;break}}if(_x${ci}){${detail(`!_a${ci}.has(_k${ci}[_i])`)}}`
4908
4922
  }
4923
+ // When every declared property is required, a clean object has exactly the
4924
+ // declared keys: if the enumerated count equals the declared count and
4925
+ // every declared name is there, the enumerated set is the declared set and
4926
+ // nothing is extra. That is the verdict generator's count, and it skips
4927
+ // comparing each key against every name, which kept this function over
4928
+ // twice the verdict's cost on an accepted document. Anything else, a
4929
+ // different count or a missing name, falls through to the scan, which
4930
+ // names the extra keys. A name Object.prototype carries answers `in`
4931
+ // through the prototype without being enumerated, so those stay on the
4932
+ // scan.
4933
+ const req = new Set(Array.isArray(schema.required) ? schema.required : [])
4934
+ if (propKeys.length > 0 && propKeys.every((k) => req.has(k) && !PROTO_NAMES.has(k))) {
4935
+ const present = propKeys.map((k) => `${JSON.stringify(k)} in ${v}`).join('&&')
4936
+ body = `let _n${ci}=0;for(const _f${ci} in ${v})_n${ci}++;if(_n${ci}!==${propKeys.length}||!(${present})){${body}}`
4937
+ }
4909
4938
  lines.push(isObj
4910
4939
  ? `{${body}}`
4911
4940
  : `if(typeof ${v}==='object'&&${v}!==null&&!Array.isArray(${v})){${body}}`)
package/lib/tier0.js CHANGED
@@ -46,6 +46,8 @@ const F_MULT = 16;
46
46
  // itself; see ownKeyExpr in js-compiler.js.
47
47
  const PROTO_NAMES = new Set([...Object.getOwnPropertyNames(Object.prototype), '__proto__']);
48
48
  const _hop = Object.prototype.hasOwnProperty;
49
+ // Deno removes the __proto__ accessor; read the prototype another way there.
50
+ const _PN = ({}).__proto__ === Object.prototype;
49
51
 
50
52
  function primConstraint(key, propSchema) {
51
53
  const t = propSchema.type;
@@ -169,7 +171,7 @@ function tier0ValidateObject(plan, data) {
169
171
  let v = data[c.key];
170
172
  // Presence is an own-property question: a value the object inherits is
171
173
  // treated as absent, as the interpreted engine treats it.
172
- if (v !== undefined && (c.protoName || data.__proto__ !== Object.prototype) && !_hop.call(data, c.key)) v = undefined;
174
+ if (v !== undefined && (c.protoName || (_PN ? data.__proto__ : Object.getPrototypeOf(data)) !== Object.prototype) && !_hop.call(data, c.key)) v = undefined;
173
175
  if (v === undefined) {
174
176
  if (reqMask & (1 << i)) return false;
175
177
  continue;
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.32.0';
10
+ module.exports = '1.32.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ata-validator",
3
- "version": "1.32.0",
3
+ "version": "1.32.1",
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_validate_json_scanner_cost.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_error_accumulator_collision.js && node tests/test_uri_helper_parity.js && node tests/test_uri_fast_path.js && node tests/test_extend_verdict.js && node tests/test_ipv4_regex.js && node tests/test_ipv6_fast_path.js && node tests/test_nested_recursion_decline.js && node tests/test_generator_error_content.js && node tests/test_inherited_key_presence.js && node tests/test_plan_source.js && node tests/test_fused_remove_additional.js && node tests/test_runtime_parse.js && node tests/test_formats_single_pass.js && node tests/test_email_format_cost.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_deferred_def_scope.js && node tests/test_node_scoped_ctx_flags.js && node tests/test_fast_slot_exhaustion.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_additional_props_combined_cost.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_single_pass_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_targeted_positions.js && node tests/test_position_map_cost.js && node tests/test_targeted_positions_cost.js && node tests/test_aot_staleness.js && node tests/test_file_positions.js && node tests/test_aot_positions_cost.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_validate_json_scanner_cost.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_error_accumulator_collision.js && node tests/test_uri_helper_parity.js && node tests/test_uri_fast_path.js && node tests/test_extend_verdict.js && node tests/test_ipv4_regex.js && node tests/test_ipv6_fast_path.js && node tests/test_nested_recursion_decline.js && node tests/test_generator_error_content.js && node tests/test_inherited_key_presence.js && node tests/test_proto_accessor.js && node tests/test_plan_source.js && node tests/test_fused_remove_additional.js && node tests/test_runtime_parse.js && node tests/test_formats_single_pass.js && node tests/test_email_format_cost.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_deferred_def_scope.js && node tests/test_node_scoped_ctx_flags.js && node tests/test_fast_slot_exhaustion.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_additional_props_combined_cost.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_single_pass_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_targeted_positions.js && node tests/test_position_map_cost.js && node tests/test_targeted_positions_cost.js && node tests/test_aot_staleness.js && node tests/test_file_positions.js && node tests/test_aot_positions_cost.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",
@@ -121,13 +121,13 @@
121
121
  "LICENSE"
122
122
  ],
123
123
  "optionalDependencies": {
124
- "@ata-validator/native-darwin-arm64": "1.32.0",
125
- "@ata-validator/native-darwin-x64": "1.32.0",
126
- "@ata-validator/native-linux-arm64-gnu": "1.32.0",
127
- "@ata-validator/native-linux-arm64-musl": "1.32.0",
128
- "@ata-validator/native-linux-x64-gnu": "1.32.0",
129
- "@ata-validator/native-linux-x64-musl": "1.32.0",
130
- "@ata-validator/native-win32-x64": "1.32.0"
124
+ "@ata-validator/native-darwin-arm64": "1.32.1",
125
+ "@ata-validator/native-darwin-x64": "1.32.1",
126
+ "@ata-validator/native-linux-arm64-gnu": "1.32.1",
127
+ "@ata-validator/native-linux-arm64-musl": "1.32.1",
128
+ "@ata-validator/native-linux-x64-gnu": "1.32.1",
129
+ "@ata-validator/native-linux-x64-musl": "1.32.1",
130
+ "@ata-validator/native-win32-x64": "1.32.1"
131
131
  },
132
132
  "peerDependencies": {
133
133
  "yaml": "^2.0.0"