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.
- package/lib/js-compiler.js +35 -6
- package/lib/tier0.js +3 -1
- package/lib/version.js +1 -1
- package/package.json +9 -9
package/lib/js-compiler.js
CHANGED
|
@@ -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
|
-
|
|
922
|
-
|
|
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
|
-
|
|
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] ===
|
|
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(
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "1.32.
|
|
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.
|
|
125
|
-
"@ata-validator/native-darwin-x64": "1.32.
|
|
126
|
-
"@ata-validator/native-linux-arm64-gnu": "1.32.
|
|
127
|
-
"@ata-validator/native-linux-arm64-musl": "1.32.
|
|
128
|
-
"@ata-validator/native-linux-x64-gnu": "1.32.
|
|
129
|
-
"@ata-validator/native-linux-x64-musl": "1.32.
|
|
130
|
-
"@ata-validator/native-win32-x64": "1.32.
|
|
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"
|