Skip to content

chore: bump ata-validator from 0.5.1 to 1.7.2 - #3

Closed
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/ata-validator-1.7.2
Closed

dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/ata-validator-1.7.2

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Aug 28, 2026

Copy link
Copy Markdown

Bumps ata-validator from 0.5.1 to 1.7.2.

Release notes

Sourced from ata-validator's releases.

v1.7.2

Fixed

  • enum compared object members by their serialized form, so {"b": 2, "a": 1} was rejected against enum: [{"a": 1, "b": 2}]. JSON Schema compares instances by value: two objects with the same members are equal whatever order their keys were written in. All three code generation paths did this, so they agreed with each other and disagreed with the interpreted engine, which has always compared structurally. const was already correct but reached the answer by building a canonical string on every call. Both now use one structural comparison hoisted per compiled function. The official suite does not cover reordered keys for enum, and the entry-point agreement test compares the generators against each other, so neither would have caught this; tests/test_value_equality.js pins the answer through every engine that can produce one and runs as part of npm test.
  • A draft-07 document passed through the schemas option was rejected with "Schema in schemas option must have $id" whenever it carried $ref next to $id. Draft-07 ignores every keyword sitting beside $ref, so normalization drops them and $id goes with them, which is the right reading for evaluation: the reference resolves against the URI the document was retrieved from, not the $id it declares. It is the wrong reading for registration, where $id is the only name the caller gave the document. The identity is now read from what the caller passed when normalization has dropped it, so such a document registers under its $id in the array form and is addressable by both its retrieval URI and its $id in the map form. A document that declares no $id at all is still refused, and a fragment-only $id is still an anchor rather than a document name. This is what made all 23 remote-reference cases of the draft-07 suite error out in the Bowtie compliance report; they now answer, and answer correctly.

Changed

  • The closure-tree compiler now covers every schema the interpreted engine accepts. It previously declined unevaluatedProperties/unevaluatedItems and $dynamicRef in any schema with more than one resource, which left 192 of the 987 suite schemas walking the generic evaluator; that count is now zero. Annotations flow through the compiled tree: the compiler decides at compile time which nodes anyone reads annotations from, and those nodes carry a record that in-place children write into directly, with a failed child rolled back by truncating the record rather than by allocating a fresh one per child. $dynamicRef resolves against the dynamic scope computed at compile time, so multi-resource schemas no longer search it per call. A schema whose compiled graph has no cycle drops the recursion guard and the (schema, data) stack entirely. An unresolvable $ref compiles into the same runtime rejection the evaluator produces instead of declining the schema.
  • Measured on the official suite with prebuilt validators, several runs each on the same machine: draft 2020-12 went from 94 ns to 77-80 ns per case overall, and the cases that route to the interpreted engine from about 240 ns to about 125 ns when they accept and 235 ns to 160 ns when they reject. Draft 7 went from 59 ns to 49 ns overall. The metaschema-validation case, the worst outlier in the suite, went from 5.5 µs to about 1.4 µs. On a longer steady-state loop over the same suite, where construction is not part of what is timed, draft 2020-12 went from 46 ns to 43 ns per case and draft 7 from 33 ns to 29 ns.
  • The value-level keywords of a schema node are compiled into closures over their own operands instead of being answered by a generic evaluator that re-reads a dozen presence flags off the plan on every call. The type of the value is computed once per node rather than once per keyword group, and a node whose keywords never need it does not compute it at all.
  • uniqueItems on arrays whose item type is not known ahead of time no longer builds a canonicalizing closure and a Set on every call. The helpers are hoisted once per compiled function; arrays of twelve items or fewer compare pairwise with a structural equality that ignores key order and allocates nothing, and longer arrays keep the Set, using canonical strings only once an object actually appears. Over the draft 7 suite the uniqueItems cases went from 125 ns to 24 ns each.
  • ARCHITECTURE.md documents the interpreted engine and the closure-tree compiler, and no longer claims $dynamicRef falls back to the native engine, which stopped being true in 1.7.1.

1.7.1: errors are paid for when read

A performance release, prompted by a benchmark from Jason Desrosiers that ran the official suite through prebuilt validators and read only .valid. On that shape ata went from 778 ns to about 150 ns per call: errors are now materialized on first read instead of on every rejection, the interpreted engine compiles schemas into a tree of plain closures (no new Function, so it holds under a CSP), and the verdict path carries no error machinery at all. Error output is unchanged, held byte-for-byte by differential tests over 2,864 suite cases.

Added

  • A closure-tree compiler for the interpreted engine. A schema the code generator declines is compiled into a tree of plain closures, one per schema node, with every keyword branch decided at compile time and $ref targets resolved once; no source generation and no new Function, so it works under a CSP and on Workers. Scope: schemas without unevaluatedProperties/unevaluatedItems, and $dynamicRef only in single-resource schemas; everything else keeps the generic evaluator. tests/test_plan_compiler.js holds the compiled tree to byte-identical verdicts and errors against the evaluator over 2,864 suite cases.

Changed

  • Plans that check only value-level keywords (most leaves of any schema) skip the evaluator's prologue entirely; $ref resolutions are cached with their planned target on the plan itself; the dynamic scope is pushed and popped in place instead of copied per resource. Rejection results are a small class with the errors accessor on the prototype, since defining a getter inside an object literal builds a closure and an accessor property on every rejection, which was the single largest cost on the rejection path.
  • The interpreted engine gained a verdict-only mode: isValidObject() and the internal fast checks walk the schema without constructing a single error object, message string or scratch array. On an interpreter-routed schema the boolean check dropped from 894 ns to 70 ns.
  • Object validation for $dynamicRef schemas no longer routes to the native engine. The interpreted engine has scored the same on every $dynamicRef case of the suite since the dynamic-scope fix in 1.7.0, needs no addon, and carries the verdict-only mode; the suite's $dynamicRef rejects dropped from about 1.7 µs to the interpreter's cost.
  • String length bounds decide from the UTF-16 length where possible: a string's code point count always sits between half its length and its length, so minLength/maxLength only count code points inside the narrow band where the answer is genuinely uncertain. The surrogate test is a single wraparound compare. The code generator already worked this way; the interpreter and the closure path now match it.
  • Errors are paid for when read, not when produced. validate() answers the verdict from the fastest engine for the schema and materializes errors through a cached getter on first access; declaration-order sorting and enrichment (received value, suggestions, source frames) moved with it into one presentation layer. A caller that only reads .valid, which is every gateway check, no longer pays for error construction at all. The output of .errors is byte-for-byte what it was. Measured on a suite-shaped benchmark of prebuilt validators over 1,052 mixed valid and invalid cases, validate().valid went from 778 ns to about 150 ns per call, ahead of every error-capable validator we measured, and a rejection that never has its errors read now costs less than abortEarly mode used to. One observable edge: mutating the data between validate() and the first read of .errors now reflects the mutated data in the errors, and if the mutation makes the data valid the errors fall back to a single generic entry.

1.7.0: every path gives the same verdict

ata has four code generation entry points, a closure compiler, an interpreter, a native walker and a set of buffer APIs. This release adds tests that run the official suite through each of them and fail on any split verdict. They found 157 disagreements between the code generators and 245 between the buffer APIs and validate(), 195 of those in the accepting direction. All are fixed or routed, the tests run in npm test, and the counts are held at zero.

Draft-07 is now read by its own rules, meta-schema references resolve from vendored copies, and the official suite stands at 1298 of 1299, 927 of 927 and 1133 of 1133, the same figures with code generation blocked. The interpreted engine is 4 to 14 times faster, and the linear-time pattern matcher runs a lazy DFA that sits within 1.2 to 3.5 times of V8's RegExp on typical patterns.

Fixed

  • The four code generation entry points disagreed with each other on 157 instances of the official suite. Most of it was the closure compiler, the boolean fallback behind isValidObject() when the code generator declines a schema: it ignored unevaluatedProperties and unevaluatedItems outright, treated a self-referencing $ref: "#" as always true, skipped additionalProperties whenever no properties map sat next to it, and passed strings in date-time, time, uri and duration format without checking them. Each of those accepted input it should have rejected. It now declines those schemas, so they reach an engine that handles them. The remaining disagreements were wrong rejections shared by both boolean paths: required, minProperties and maxProperties applied to non-objects, multipleOf had no tolerance for fractional divisors, const and enum compared objects by key order, and items started at index 0 when prefixItems was present. isValidObject() and validate() now agree on every suite instance.
  • A dependentSchemas branch carrying additionalProperties: false had that check hoisted out of its condition to the top level of the compiled function, so the restriction applied whether or not the triggering property was present.
  • The error path counted a property matched by patternProperties as additional under additionalProperties: false. The same path now reports the real pointer (#/patternProperties/<pattern>/...) for a failing pattern subschema instead of the synthetic #/patternProperties, so source frames resolve for those errors.
  • The buffer APIs (isValid, isValidJSON above the simdjson threshold, countValid, batchIsValid, isValidNDJSON, isValidParallel, isValidPrepadded) disagreed with validate() on 245 of 2222 suite cases, and in 195 of those they accepted a document validate() rejects. The native walker behind them does not handle contains, unevaluated*, dependencies, dependentSchemas, dependentRequired, propertyNames, patternProperties, tuple-form items and prefixItems, cross-document $ref, embedded $id, an empty enum, a boolean root schema, Unicode property escapes in pattern, or the hostname, date-time, time, uri-reference and duration formats. For a schema using any of those, every buffer API now parses the bytes and answers through validate(); lib/buffer-gate.js holds the list. Schemas without them keep the zero-copy path. tests/test_buffer_path_parity.js now compares all three dialects, 3359 cases, and holds the disagreement count at zero.
  • A value failing a patternProperties subschema was reported at runtime as a generic "value invalid for key" error on the parent object with the synthetic pointer #/patternProperties. The subschema is now generated in place, so the error comes from its own keyword, at the key's path (/x-flag), with the real pointer (#/patternProperties/^x-/type), and source frames resolve for it. Patterns containing / or ' produce a correctly escaped pointer.
  • tests/test_codegen_entrypoint_agreement.js drives the whole suite through each entry point directly and fails on any split verdict. It runs as part of npm test.

Added

  • A $ref to a dialect's meta-schema (https://json-schema.org/draft/2020-12/schema, http://json-schema.org/draft-07/schema#, any http/https or trailing-# spelling) resolves from copies vendored in lib/metaschemas.js, so "validate this schema against its dialect" works with no registry and no network. A copy supplied through schemas or addSchema() still wins. The 2020-12 meta-schema is eight documents joined by $dynamicRef; see the routing change below.

  • validator.engine() reports which engine answers validate() for the schema: 'codegen', 'closure', 'native' or 'interpreter'. A diagnostic for startup logs and benchmarks. Measured over fourteen request-shaped schemas (body, params, query, shared $ref, oneOf, if/then, local $defs), thirteen take the generated path; patternProperties with additionalProperties: false is the one that goes to the interpreter.

  • formatMode: 'inject' for toStandaloneModule, bundleStandalone, bundleCompact and build(). The output carries no custom format source; it exports setFormats(map) and looks each format up from that registry at validation time, with a named error if one is missing. This is for formats that cannot be serialized: functions that close over variables, bound functions, or code rewritten by coverage and transpile steps. The default 'embed' is unchanged in behavior, but it now checks each function's source at build time and throws with the format's name when it would not survive embedding, instead of emitting a module that fails on first use.

... (truncated)

Changelog

Sourced from ata-validator's changelog.

1.7.2 - 2026-08-24

Fixed

  • enum compared object members by their serialized form, so {"b": 2, "a": 1} was rejected against enum: [{"a": 1, "b": 2}]. JSON Schema compares instances by value: two objects with the same members are equal whatever order their keys were written in. All three code generation paths did this, so they agreed with each other and disagreed with the interpreted engine, which has always compared structurally. const was already correct but reached the answer by building a canonical string on every call. Both now use one structural comparison hoisted per compiled function. The official suite does not cover reordered keys for enum, and the entry-point agreement test compares the generators against each other, so neither would have caught this; tests/test_value_equality.js pins the answer through every engine that can produce one and runs as part of npm test.
  • A draft-07 document passed through the schemas option was rejected with "Schema in schemas option must have $id" whenever it carried $ref next to $id. Draft-07 ignores every keyword sitting beside $ref, so normalization drops them and $id goes with them, which is the right reading for evaluation: the reference resolves against the URI the document was retrieved from, not the $id it declares. It is the wrong reading for registration, where $id is the only name the caller gave the document. The identity is now read from what the caller passed when normalization has dropped it, so such a document registers under its $id in the array form and is addressable by both its retrieval URI and its $id in the map form. A document that declares no $id at all is still refused, and a fragment-only $id is still an anchor rather than a document name. This is what made all 23 remote-reference cases of the draft-07 suite error out in the Bowtie compliance report; they now answer, and answer correctly.

Changed

  • The closure-tree compiler now covers every schema the interpreted engine accepts. It previously declined unevaluatedProperties/unevaluatedItems and $dynamicRef in any schema with more than one resource, which left 192 of the 987 suite schemas walking the generic evaluator; that count is now zero. Annotations flow through the compiled tree: the compiler decides at compile time which nodes anyone reads annotations from, and those nodes carry a record that in-place children write into directly, with a failed child rolled back by truncating the record rather than by allocating a fresh one per child. $dynamicRef resolves against the dynamic scope computed at compile time, so multi-resource schemas no longer search it per call. A schema whose compiled graph has no cycle drops the recursion guard and the (schema, data) stack entirely. An unresolvable $ref compiles into the same runtime rejection the evaluator produces instead of declining the schema.
  • Measured on the official suite with prebuilt validators, several runs each on the same machine: draft 2020-12 went from 94 ns to 77-80 ns per case overall, and the cases that route to the interpreted engine from about 240 ns to about 125 ns when they accept and 235 ns to 160 ns when they reject. Draft 7 went from 59 ns to 49 ns overall. The metaschema-validation case, the worst outlier in the suite, went from 5.5 µs to about 1.4 µs. On a longer steady-state loop over the same suite, where construction is not part of what is timed, draft 2020-12 went from 46 ns to 43 ns per case and draft 7 from 33 ns to 29 ns.
  • The value-level keywords of a schema node are compiled into closures over their own operands instead of being answered by a generic evaluator that re-reads a dozen presence flags off the plan on every call. The type of the value is computed once per node rather than once per keyword group, and a node whose keywords never need it does not compute it at all.
  • uniqueItems on arrays whose item type is not known ahead of time no longer builds a canonicalizing closure and a Set on every call. The helpers are hoisted once per compiled function; arrays of twelve items or fewer compare pairwise with a structural equality that ignores key order and allocates nothing, and longer arrays keep the Set, using canonical strings only once an object actually appears. Over the draft 7 suite the uniqueItems cases went from 125 ns to 24 ns each.
  • ARCHITECTURE.md documents the interpreted engine and the closure-tree compiler, and no longer claims $dynamicRef falls back to the native engine, which stopped being true in 1.7.1.

1.7.1 - 2026-08-23

Added

  • A closure-tree compiler for the interpreted engine. A schema the code generator declines is compiled into a tree of plain closures, one per schema node, with every keyword branch decided at compile time and $ref targets resolved once; no source generation and no new Function, so it works under a CSP and on Workers. Scope: schemas without unevaluatedProperties/unevaluatedItems, and $dynamicRef only in single-resource schemas; everything else keeps the generic evaluator. tests/test_plan_compiler.js holds the compiled tree to byte-identical verdicts and errors against the evaluator over 2,864 suite cases.

Changed

  • Plans that check only value-level keywords (most leaves of any schema) skip the evaluator's prologue entirely; $ref resolutions are cached with their planned target on the plan itself; the dynamic scope is pushed and popped in place instead of copied per resource. Rejection results are a small class with the errors accessor on the prototype, since defining a getter inside an object literal builds a closure and an accessor property on every rejection, which was the single largest cost on the rejection path.
  • The interpreted engine gained a verdict-only mode: isValidObject() and the internal fast checks walk the schema without constructing a single error object, message string or scratch array. On an interpreter-routed schema the boolean check dropped from 894 ns to 70 ns.
  • Object validation for $dynamicRef schemas no longer routes to the native engine. The interpreted engine has scored the same on every $dynamicRef case of the suite since the dynamic-scope fix in 1.7.0, needs no addon, and carries the verdict-only mode; the suite's $dynamicRef rejects dropped from about 1.7 µs to the interpreter's cost.
  • String length bounds decide from the UTF-16 length where possible: a string's code point count always sits between half its length and its length, so minLength/maxLength only count code points inside the narrow band where the answer is genuinely uncertain. The surrogate test is a single wraparound compare. The code generator already worked this way; the interpreter and the closure path now match it.
  • Errors are paid for when read, not when produced. validate() answers the verdict from the fastest engine for the schema and materializes errors through a cached getter on first access; declaration-order sorting and enrichment (received value, suggestions, source frames) moved with it into one presentation layer. A caller that only reads .valid, which is every gateway check, no longer pays for error construction at all. The output of .errors is byte-for-byte what it was. Measured on a suite-shaped benchmark of prebuilt validators over 1,052 mixed valid and invalid cases, validate().valid went from 778 ns to about 150 ns per call, ahead of every error-capable validator we measured, and a rejection that never has its errors read now costs less than abortEarly mode used to. One observable edge: mutating the data between validate() and the first read of .errors now reflects the mutated data in the errors, and if the mutation makes the data valid the errors fall back to a single generic entry.

1.7.0 - 2026-08-23

Fixed

  • The four code generation entry points disagreed with each other on 157 instances of the official suite. Most of it was the closure compiler, the boolean fallback behind isValidObject() when the code generator declines a schema: it ignored unevaluatedProperties and unevaluatedItems outright, treated a self-referencing $ref: "#" as always true, skipped additionalProperties whenever no properties map sat next to it, and passed strings in date-time, time, uri and duration format without checking them. Each of those accepted input it should have rejected. It now declines those schemas, so they reach an engine that handles them. The remaining disagreements were wrong rejections shared by both boolean paths: required, minProperties and maxProperties applied to non-objects, multipleOf had no tolerance for fractional divisors, const and enum compared objects by key order, and items started at index 0 when prefixItems was present. isValidObject() and validate() now agree on every suite instance.
  • A dependentSchemas branch carrying additionalProperties: false had that check hoisted out of its condition to the top level of the compiled function, so the restriction applied whether or not the triggering property was present.
  • The error path counted a property matched by patternProperties as additional under additionalProperties: false. The same path now reports the real pointer (#/patternProperties/<pattern>/...) for a failing pattern subschema instead of the synthetic #/patternProperties, so source frames resolve for those errors.
  • The buffer APIs (isValid, isValidJSON above the simdjson threshold, countValid, batchIsValid, isValidNDJSON, isValidParallel, isValidPrepadded) disagreed with validate() on 245 of 2222 suite cases, and in 195 of those they accepted a document validate() rejects. The native walker behind them does not handle contains, unevaluated*, dependencies, dependentSchemas, dependentRequired, propertyNames, patternProperties, tuple-form items and prefixItems, cross-document $ref, embedded $id, an empty enum, a boolean root schema, Unicode property escapes in pattern, or the hostname, date-time, time, uri-reference and duration formats. For a schema using any of those, every buffer API now parses the bytes and answers through validate(); lib/buffer-gate.js holds the list. Schemas without them keep the zero-copy path. tests/test_buffer_path_parity.js now compares all three dialects, 3359 cases, and holds the disagreement count at zero.
  • A value failing a patternProperties subschema was reported at runtime as a generic "value invalid for key" error on the parent object with the synthetic pointer #/patternProperties. The subschema is now generated in place, so the error comes from its own keyword, at the key's path (/x-flag), with the real pointer (#/patternProperties/^x-/type), and source frames resolve for it. Patterns containing / or ' produce a correctly escaped pointer.
  • tests/test_codegen_entrypoint_agreement.js drives the whole suite through each entry point directly and fails on any split verdict. It runs as part of npm test.

Added

  • A $ref to a dialect's meta-schema (https://json-schema.org/draft/2020-12/schema, http://json-schema.org/draft-07/schema#, any http/https or trailing-# spelling) resolves from copies vendored in lib/metaschemas.js, so "validate this schema against its dialect" works with no registry and no network. A copy supplied through schemas or addSchema() still wins. The 2020-12 meta-schema is eight documents joined by $dynamicRef; see the routing change below.

  • validator.engine() reports which engine answers validate() for the schema: 'codegen', 'closure', 'native' or 'interpreter'. A diagnostic for startup logs and benchmarks. Measured over fourteen request-shaped schemas (body, params, query, shared $ref, oneOf, if/then, local $defs), thirteen take the generated path; patternProperties with additionalProperties: false is the one that goes to the interpreter.

  • formatMode: 'inject' for toStandaloneModule, bundleStandalone, bundleCompact and build(). The output carries no custom format source; it exports setFormats(map) and looks each format up from that registry at validation time, with a named error if one is missing. This is for formats that cannot be serialized: functions that close over variables, bound functions, or code rewritten by coverage and transpile steps. The default 'embed' is unchanged in behavior, but it now checks each function's source at build time and throws with the format's name when it would not survive embedding, instead of emitting a module that fails on first use.

Changed

  • Draft-07 is now read by its own rules rather than as 2020-12 with renamed keywords. A schema object carrying $ref is that reference and nothing else, so sibling keywords, $id included, are ignored, as the draft specifies. A fragment-only $id ("$id": "#name") is a plain-name anchor. A document supplied through schemas or addSchema() that declares no $schema of its own is read under the root's draft. JSON Pointers written against array-form items still resolve after the keyword is normalized to prefixItems. Schemas that declare no $schema are unaffected. Draft 7 on the official suite goes from 916 to 927 of 927.

... (truncated)

Commits
  • fc17966 docs: record the enum equality fix and the leaf compilation in the changelog
  • 5f901d3 fix: compare enum and const values structurally, not by their serialized form
  • 7b73e39 perf: compile the leaf verdict checks instead of re-reading plan flags per call
  • d57c238 fix: register a draft-07 document that carries $ref beside $id under its decl...
  • 889227c perf: hoist uniqueItems helpers, pairwise structural compare for short arrays
  • 0697010 perf: allocation-free annotation records, no cycle guard on acyclic schemas, ...
  • aa7050d perf: compile unevaluated keywords and the multi-resource dynamic scope in th...
  • 45c864c chore: bump to 1.7.2
  • b5a828c perf: verdict-only compiled variant with no path strings on the hot walk
  • 77f27cb docs: state the measured benchmark figure precisely
  • Additional commits viewable in compare view
Maintainer changes

This version was pushed to npm by GitHub Actions, a new releaser for ata-validator since your current version.


Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Bumps [ata-validator](https://github.com/ata-core/ata-validator) from 0.5.1 to 1.7.2.
- [Release notes](https://github.com/ata-core/ata-validator/releases)
- [Changelog](https://github.com/ata-core/ata-validator/blob/master/CHANGELOG.md)
- [Commits](ata-core/ata-validator@v0.5.1...v1.7.2)

---
updated-dependencies:
- dependency-name: ata-validator
  dependency-version: 1.7.2
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code labels Aug 28, 2026
@dependabot @github

dependabot Bot commented on behalf of github Aug 31, 2026

Copy link
Copy Markdown
Author

Superseded by #4.

@dependabot dependabot Bot closed this Aug 31, 2026
@dependabot
dependabot Bot deleted the dependabot/npm_and_yarn/ata-validator-1.7.2 branch August 31, 2026 03:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants