From 235650111c81a4c9ea3eded6e0b20b0824681843 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Tue, 6 Jan 2026 13:41:26 -0700 Subject: [PATCH 01/32] ci: fix release script (#4984) Our first [GHA GitHub release failed](https://github.com/dequelabs/axe-core/actions/runs/20758308118/job/59607316910). Looks like the script expects the env which wasn't set. --- .github/workflows/deploy.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index fda5a9dec..867f60a82 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -173,6 +173,8 @@ jobs: - name: Make Release Script Executable run: chmod +x ./node-github-release.sh - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: ./node-github-release.sh validate-deploy: name: Validate Deployment From 2249a05bfbe88dfd1219ac52375de91143b2dd8d Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Tue, 13 Jan 2026 08:04:41 -0700 Subject: [PATCH 02/32] test: fix test:unit (#4989) Running `npm run test:unit` results in loads of failures. After racking my brain about why, I remembered I had a similar problem in my [fixing `npm run test:debug` pr](https://github.com/dequelabs/axe-core/pull/4769) where resetting the memoize functions results in them not being able to clear the cache between tests. Turns out that was the issue here. Note: this isn't a problem in our pr runs or nightly tests because we either call `npm run: test:unit:` directly or run `npm test` which runs all the tests in turn. This only happens when running `npm run test:unit` since the browser doesn't close between test types. --- test/core/utils/memoize.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/utils/memoize.js b/test/core/utils/memoize.js index 7c8503361..ec3e3baee 100644 --- a/test/core/utils/memoize.js +++ b/test/core/utils/memoize.js @@ -2,9 +2,9 @@ describe('axe.utils.memoize', function () { 'use strict'; it('should add the function to axe._memoizedFns', function () { - axe._memoizedFns.length = 0; + const length = axe._memoizedFns.length; axe.utils.memoize(function myFn() {}); - assert.equal(axe._memoizedFns.length, 1); + assert.equal(axe._memoizedFns.length, length + 1); }); }); From 9322148b69924d6ae2d2dd46e6109bc2fc53abd3 Mon Sep 17 00:00:00 2001 From: JustasM <59362982+JustasMonkev@users.noreply.github.com> Date: Tue, 27 Jan 2026 01:16:56 +0200 Subject: [PATCH 03/32] fix(aria-valid-attr-value): handle multiple aria-errormessage IDs (#4973) When aria-errormessage contains multiple space-separated IDs, the check now correctly verifies that all IDs are present in aria-describedby instead of failing to match the entire string against tokenized values. Closes: https://github.com/dequelabs/axe-core/issues/4957 --- lib/checks/aria/aria-errormessage-evaluate.js | 13 +++- lib/checks/aria/aria-errormessage.json | 1 + locales/_template.json | 1 + test/checks/aria/errormessage.js | 67 +++++++++++++++++-- .../aria-valid-attr-value.html | 34 ++++++++++ .../aria-valid-attr-value.json | 7 +- 6 files changed, 113 insertions(+), 10 deletions(-) diff --git a/lib/checks/aria/aria-errormessage-evaluate.js b/lib/checks/aria/aria-errormessage-evaluate.js index 2ef53f35e..977b2cce7 100644 --- a/lib/checks/aria/aria-errormessage-evaluate.js +++ b/lib/checks/aria/aria-errormessage-evaluate.js @@ -42,6 +42,12 @@ export default function ariaErrormessageEvaluate(node, options, virtualNode) { if (attr.trim() === '') { return standards.ariaAttrs['aria-errormessage'].allowEmpty; } + + const errormessageTokens = tokenList(attr); + if (errormessageTokens.length > 1) { + this.data({ messageKey: 'unsupported', values: errormessageTokens }); + return false; + } let idref; try { @@ -49,7 +55,7 @@ export default function ariaErrormessageEvaluate(node, options, virtualNode) { } catch { this.data({ messageKey: 'idrefs', - values: tokenList(attr) + values: errormessageTokens }); return undefined; } @@ -58,15 +64,16 @@ export default function ariaErrormessageEvaluate(node, options, virtualNode) { if (!isVisibleToScreenReaders(idref)) { this.data({ messageKey: 'hidden', - values: tokenList(attr) + values: errormessageTokens }); return false; } + const describedbyTokens = tokenList(virtualNode.attr('aria-describedby')); return ( getExplicitRole(idref) === 'alert' || idref.getAttribute('aria-live') === 'assertive' || idref.getAttribute('aria-live') === 'polite' || - tokenList(virtualNode.attr('aria-describedby')).indexOf(attr) > -1 + errormessageTokens.some(token => describedbyTokens.includes(token)) ); } diff --git a/lib/checks/aria/aria-errormessage.json b/lib/checks/aria/aria-errormessage.json index e238d7f65..bfc90e7f6 100644 --- a/lib/checks/aria/aria-errormessage.json +++ b/lib/checks/aria/aria-errormessage.json @@ -8,6 +8,7 @@ "fail": { "singular": "aria-errormessage value `${data.values}` must use a technique to announce the message (e.g., aria-live, aria-describedby, role=alert, etc.)", "plural": "aria-errormessage values `${data.values}` must use a technique to announce the message (e.g., aria-live, aria-describedby, role=alert, etc.)", + "unsupported": "Multiple IDs in aria-errormessage is not widely supported in assistive technologies", "hidden": "aria-errormessage value `${data.values}` cannot reference a hidden element" }, "incomplete": { diff --git a/locales/_template.json b/locales/_template.json index d1993f0d8..6bfc77bc6 100644 --- a/locales/_template.json +++ b/locales/_template.json @@ -462,6 +462,7 @@ "fail": { "singular": "aria-errormessage value `${data.values}` must use a technique to announce the message (e.g., aria-live, aria-describedby, role=alert, etc.)", "plural": "aria-errormessage values `${data.values}` must use a technique to announce the message (e.g., aria-live, aria-describedby, role=alert, etc.)", + "unsupported": "Multiple IDs in aria-errormessage is not widely supported in assistive technologies", "hidden": "aria-errormessage value `${data.values}` cannot reference a hidden element" }, "incomplete": { diff --git a/test/checks/aria/errormessage.js b/test/checks/aria/errormessage.js index fd95256b2..cef7ea31f 100644 --- a/test/checks/aria/errormessage.js +++ b/test/checks/aria/errormessage.js @@ -70,15 +70,72 @@ describe('aria-errormessage', function () { ); }); - it('sets an array of IDs in data', function () { + it('should return false if aria-errormessage has multiple ids (unsupported)', function () { + var vNode = queryFixture( + '' + + '
Error 1
' + + '
Error 2
' + ); + assert.isFalse( + axe.testUtils + .getCheckEvaluate('aria-errormessage') + .call(checkContext, null, null, vNode) + ); + assert.deepEqual(checkContext._data, { + messageKey: 'unsupported', + values: ['error1', 'error2'] + }); + }); + + it('should return false if aria-errormessage has multiple ids even when one is in aria-describedby', function () { + var vNode = queryFixture( + '' + + '
Error 1
' + + '
Error 2
' + ); + assert.isFalse( + axe.testUtils + .getCheckEvaluate('aria-errormessage') + .call(checkContext, null, null, vNode) + ); + assert.deepEqual(checkContext._data, { + messageKey: 'unsupported', + values: ['error1', 'error2'] + }); + }); + + it('should return false if aria-errormessage has multiple ids even when none are in aria-describedby', function () { + var vNode = queryFixture( + '' + + '
Other
' + + '
Error 1
' + + '
Error 2
' + ); + assert.isFalse( + axe.testUtils + .getCheckEvaluate('aria-errormessage') + .call(checkContext, null, null, vNode) + ); + assert.deepEqual(checkContext._data, { + messageKey: 'unsupported', + values: ['error1', 'error2'] + }); + }); + + it('sets an unsupported message when aria-errormessage contains multiple ids', function () { var vNode = queryFixture( '
' + '
' ); - axe.testUtils - .getCheckEvaluate('aria-errormessage') - .call(checkContext, null, null, vNode); - assert.deepEqual(checkContext._data, ['foo', 'bar', 'baz']); + assert.isFalse( + axe.testUtils + .getCheckEvaluate('aria-errormessage') + .call(checkContext, null, null, vNode) + ); + assert.deepEqual(checkContext._data, { + messageKey: 'unsupported', + values: ['foo', 'bar', 'baz'] + }); }); it('returns true when aria-errormessage is empty, if that is allowed', function () { diff --git a/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.html b/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.html index 1542a403b..cff70c3d2 100644 --- a/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.html +++ b/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.html @@ -90,6 +90,28 @@

Violations

/>
+ + +
+ +
Error message 1
+
Error message 2
+
+ +
+ +

Possible False Positives

@@ -349,6 +371,18 @@

Possible False Positives

aria-valuetext="" >
+
+ +
Error message 1
+
Error message 2
+
+
Hi
Hi2
diff --git a/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.json b/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.json index f0b46c6fc..089b2a48a 100644 --- a/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.json +++ b/test/integration/rules/aria-valid-attr-value/aria-valid-attr-value.json @@ -44,7 +44,9 @@ ["#violation43"], ["#violation44"], ["#violation45"], - ["#violation46"] + ["#violation46"], + ["#violation47"], + ["#violation48"] ], "passes": [ ["#pass1"], @@ -226,7 +228,8 @@ ["#pass188"], ["#pass189"], ["#pass190"], - ["#pass191"] + ["#pass191"], + ["#pass192"] ], "incomplete": [ ["#incomplete1"], From 2567afd5c32398c6a488240b066bb0d335f6dc6a Mon Sep 17 00:00:00 2001 From: Wilco Fiers Date: Thu, 29 Jan 2026 17:41:38 +0100 Subject: [PATCH 04/32] fix(scrollable-region-focusable): clarify the issue is in safari (#4995) Part of https://github.com/dequelabs/axe-core/issues/4830 Doesn't close the issue, but people keep reporting this as a false positive because we don't make it clear this is a Safari-only issue. Axe-core explicitly calling out a browser or screen reader is unusual, but I think the problem not doing this creates here is bigger than the overhead it would be for us to keep an eye on this and pull this out. If Safari ever addresses this the rule can be deprecated completely. See related Webkit bugs: - [WebKit#190870: Make scrollable element focusable](https://bugs.webkit.org/show_bug.cgi?id=190870) - [WebKit#277290: AX: Scrolling containers inoperable with keyboard](https://bugs.webkit.org/show_bug.cgi?id=277290) --- lib/rules/scrollable-region-focusable.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rules/scrollable-region-focusable.json b/lib/rules/scrollable-region-focusable.json index 44e02fe7e..ce3df6a9c 100644 --- a/lib/rules/scrollable-region-focusable.json +++ b/lib/rules/scrollable-region-focusable.json @@ -18,7 +18,7 @@ ], "actIds": ["0ssw9k"], "metadata": { - "description": "Ensure elements that have scrollable content are accessible by keyboard", + "description": "Ensure elements that have scrollable content are accessible by keyboard in Safari", "help": "Scrollable region must have keyboard access" }, "all": [], From 6d194964cd40d37822f423fbcebfe7959257869a Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Tue, 3 Feb 2026 09:37:57 -0700 Subject: [PATCH 05/32] chore: sync generated files (#5007) Since the [automatic action failed](https://github.com/dequelabs/axe-core/actions/runs/21486657500/job/61897684879) had to manually do it. --- doc/rule-descriptions.md | 2 +- locales/_template.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 6858eb630..a21155744 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -66,7 +66,7 @@ | [no-autoplay-audio](https://dequeuniversity.com/rules/axe/4.11/no-autoplay-audio?application=RuleDescription) | Ensure <video> or <audio> elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio | Moderate | cat.time-and-media, wcag2a, wcag142, TTv5, TT2.a, EN-301-549, EN-9.1.4.2, ACT, RGAAv4, RGAA-4.10.1 | needs review | [80f0bf](https://act-rules.github.io/rules/80f0bf) | | [object-alt](https://dequeuniversity.com/rules/axe/4.11/object-alt?application=RuleDescription) | Ensure <object> elements have alternative text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, EN-301-549, EN-9.1.1.1, RGAAv4, RGAA-1.1.6 | failure, needs review | [8fc3b6](https://act-rules.github.io/rules/8fc3b6) | | [role-img-alt](https://dequeuniversity.com/rules/axe/4.11/role-img-alt?application=RuleDescription) | Ensure [role="img"] elements have alternative text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, TTv5, TT7.a, EN-301-549, EN-9.1.1.1, ACT, RGAAv4, RGAA-1.1.1 | failure, needs review | [23a2a8](https://act-rules.github.io/rules/23a2a8) | -| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.11/scrollable-region-focusable?application=RuleDescription) | Ensure elements that have scrollable content are accessible by keyboard | Serious | cat.keyboard, wcag2a, wcag211, wcag213, TTv5, TT4.a, EN-301-549, EN-9.2.1.1, EN-9.2.1.3, RGAAv4, RGAA-7.3.2 | failure | [0ssw9k](https://act-rules.github.io/rules/0ssw9k) | +| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.11/scrollable-region-focusable?application=RuleDescription) | Ensure elements that have scrollable content are accessible by keyboard in Safari | Serious | cat.keyboard, wcag2a, wcag211, wcag213, TTv5, TT4.a, EN-301-549, EN-9.2.1.1, EN-9.2.1.3, RGAAv4, RGAA-7.3.2 | failure | [0ssw9k](https://act-rules.github.io/rules/0ssw9k) | | [select-name](https://dequeuniversity.com/rules/axe/4.11/select-name?application=RuleDescription) | Ensure select element has an accessible name | Critical | cat.forms, wcag2a, wcag412, section508, section508.22.n, TTv5, TT5.c, EN-301-549, EN-9.4.1.2, ACT, RGAAv4, RGAA-11.1.1 | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | | [server-side-image-map](https://dequeuniversity.com/rules/axe/4.11/server-side-image-map?application=RuleDescription) | Ensure that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f, TTv5, TT4.a, EN-301-549, EN-9.2.1.1, RGAAv4, RGAA-1.1.4 | needs review | | | [summary-name](https://dequeuniversity.com/rules/axe/4.11/summary-name?application=RuleDescription) | Ensure summary elements have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, TTv5, TT6.a, EN-301-549, EN-9.4.1.2 | failure, needs review | | diff --git a/locales/_template.json b/locales/_template.json index 6bfc77bc6..70203bd75 100644 --- a/locales/_template.json +++ b/locales/_template.json @@ -358,7 +358,7 @@ "help": "scope attribute should be used correctly" }, "scrollable-region-focusable": { - "description": "Ensure elements that have scrollable content are accessible by keyboard", + "description": "Ensure elements that have scrollable content are accessible by keyboard in Safari", "help": "Scrollable region must have keyboard access" }, "select-name": { From 97f1190c22e255e24eb78c8749e100b7c762aa3f Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Tue, 3 Feb 2026 09:38:12 -0700 Subject: [PATCH 06/32] ci: fix update-generated-files workflow (#5006) It would seem that the `GITHUB_OUTPUT` syntax [does not allow line breaks](https://github.com/orgs/community/discussions/106666). Since the output to `git status --porcelain` produces a line with 2 changes ``` M doc/rule-descriptions.md M locales/_template.json ``` removing the line breaks from the variable should fix the problem. --- .github/workflows/update-generated-files.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-generated-files.yaml b/.github/workflows/update-generated-files.yaml index 1968e89c5..6ac667002 100644 --- a/.github/workflows/update-generated-files.yaml +++ b/.github/workflows/update-generated-files.yaml @@ -29,7 +29,7 @@ jobs: - name: Check for changes id: changes run: | - changes=$(git status --porcelain) + changes=$(git status --porcelain | tr -d '\n') # see https://unix.stackexchange.com/a/509498 echo $changes | grep . && echo "Changes detected" || echo "No changes" echo "changes=$changes" >> "$GITHUB_OUTPUT" From 5be3a2bff0d5e344dafc825235f34aa4d1e762ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Feb 2026 09:56:21 -0700 Subject: [PATCH 07/32] chore: bump globals from 16.5.0 to 17.1.0 (#5005) Bumps [globals](https://github.com/sindresorhus/globals) from 16.5.0 to 17.1.0.
Release notes

Sourced from globals's releases.

v17.1.0

  • Add webpack and rspack globals (#333) 65cae73

https://github.com/sindresorhus/globals/compare/v17.0.0...v17.1.0

v17.0.0

Breaking

  • Split audioWorklet environment from browser (#320) 7bc293e

Improvements

  • Update globals (#329) ebe1063
  • Get all browser globals from both chrome and firefox (#321) 59ceff8
  • Add bunBuiltin environment (#324) 1bc6e3b
  • Add denoBuiltin environment (#324) 1bc6e3b
  • Add paintWorklet environment (#323) 4b78f56
  • Add sharedWorker environment (#322) 4a02a85

https://github.com/sindresorhus/globals/compare/v16.5.0...v17.0.0

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=globals&package-manager=npm_and_yarn&previous-version=16.5.0&new-version=17.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) 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-automerge-start) [//]: # (dependabot-automerge-end) ---
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 merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show 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)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index ae7ad8e7b..840d7830d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,7 @@ "eslint-plugin-mocha-no-only": "^1.2.0", "execa": "5.x", "glob": "^10.3.10", - "globals": "^16.0.0", + "globals": "^17.1.0", "grunt": "^1.5.3", "grunt-babel": "^8.0.0", "grunt-bytesize": "^0.2.0", @@ -6376,9 +6376,9 @@ } }, "node_modules/globals": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", - "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.1.0.tgz", + "integrity": "sha512-8HoIcWI5fCvG5NADj4bDav+er9B9JMj2vyL2pI8D0eismKyUvPLTSs+Ln3wqhwcp306i73iyVnEKx3F6T47TGw==", "dev": true, "engines": { "node": ">=18" @@ -17922,9 +17922,9 @@ } }, "globals": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", - "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.1.0.tgz", + "integrity": "sha512-8HoIcWI5fCvG5NADj4bDav+er9B9JMj2vyL2pI8D0eismKyUvPLTSs+Ln3wqhwcp306i73iyVnEKx3F6T47TGw==", "dev": true }, "globule": { diff --git a/package.json b/package.json index 1fdfb77ce..afb51ce7a 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,7 @@ "eslint-plugin-mocha-no-only": "^1.2.0", "execa": "5.x", "glob": "^10.3.10", - "globals": "^16.0.0", + "globals": "^17.1.0", "grunt": "^1.5.3", "grunt-babel": "^8.0.0", "grunt-bytesize": "^0.2.0", From 818e197db6e90fe4adca03d738ede4e03664bcc3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Feb 2026 11:26:25 -0700 Subject: [PATCH 08/32] chore: bump jquery from 3.7.1 to 4.0.0 (#5004) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [jquery](https://github.com/jquery/jquery) from 3.7.1 to 4.0.0.
Release notes

Sourced from jquery's releases.

Release 4.0.0

Changelog

https://blog.jquery.com/2026/01/17/jquery-4-0-0/

Ajax

  • Don't treat array data as binary (992a1911)
  • Allow processData: true even for binary data (ce264e07)
  • Support binary data (including FormData) (a7ed9a7b)
  • Support headers for script transport even when cross-domain (#5142, 6d136443)
  • Support null as success functions in jQuery.get (#4989, 74978b7e)
  • Don't auto-execute scripts unless dataType provided (#4822, 025da4dd)
  • Make responseJSON work for erroneous same-domain JSONP requests (68b4ec59)
  • Execute JSONP error script responses (#4771, a1e619b0)
  • Avoid CSP errors in the script transport for async requests (#3969, 07a8e4a1)
  • Drop the json to jsonp auto-promotion logic (#1799, #3376, e7b3bc48)
  • Overwrite s.contentType with content-type header value, if any (#4119, 7fb90a6b)
  • Deprecate AJAX event aliases, inline event/alias into deprecated (23d53928)
  • Do not execute scripts for unsuccessful HTTP responses (#4250, 50871a5a)
  • Simplify jQuery.ajaxSettings.xhr (#1967, abdc89ac)

Attributes

  • Make .attr( name, false ) remove for all non-ARIA attrs (#5388, 063831b6)
  • Shave off a couple of bytes (b40a4807)
  • Don't stringify attributes in the setter (#4948, 4250b628)
  • Drop the toggleClass(boolean|undefined) signature (#3388, a4421101)
  • Refactor val(): don't strip carriage return, isolate IE workarounds (ff281991)
  • Don't set the type attr hook at all outside of IE (9e66fe9a)

CSS

  • Fix dimensions of table <col> elements (#5628, eca2a564)
  • Drop the cache in finalPropName (640d5825)
  • Tests: Fix tests & support tests under CSS Zoom (#5489, 071f6dba)
  • Fix reliableTrDimensions support test for initially hidden iframes (b1e66a5f)
  • Selector: Align with 3.x, remove the outer selector.js wrapper (53cf7244)
  • Make the reliableTrDimensions support test work with Bootstrap CSS (#5270, 65b85031)
  • Make offsetHeight( true ), etc. include negative margins (#3982, bce13b72)
  • Return undefined for whitespace-only CSS variable values (#5120) (7eb00196)
  • Don’t trim whitespace of undefined custom property (#5105, ed306c02)
  • Skip falsy values in addClass( array ), compress code (#4998, a338b407)
  • Justify use of rtrim on CSS property values (655c0ed5)
  • Trim whitespace surrounding CSS Custom Properties values (#4926, efadfe99)
  • Include show, hide & toggle methods in the jQuery slim build (297d18dd)
  • Remove the opacity CSS hook (865469f5)
  • Workaround buggy getComputedStyle on table rows in IE/Edge (#4490, 26415e08)
  • Don't automatically add "px" to properties with a few exceptions (#2795, 00a9c2e5)

... (truncated)

Commits
  • 4f2fae0 Release: 4.0.0
  • c838cfb Release: remove dist files from main branch
  • 9752519 Release: 4.0.0-rc.2
  • c128d5d Release: Update AUTHORS.txt
  • 5fe9c29 Build: De-dupe three authors via mailmap
  • afdd032 Build: Post beta browser tests errors to jquery/dev on Matrix
  • 546a1eb Build: Bump the github-actions group with 4 updates
  • ec738b3 Build: Fix Chrome beta tests
  • c28c26a Build: Add periodic tests on beta versions of browsers
  • f513413 Build: Bump the github-actions group with 2 updates
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=jquery&package-manager=npm_and_yarn&previous-version=3.7.1&new-version=4.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) 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-automerge-start) [//]: # (dependabot-automerge-end) ---
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 merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show 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)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 840d7830d..e8f8aa471 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "http-server": "^14.1.1", "husky": "^9.0.7", "inquirer": "^8.2.5", - "jquery": "^3.6.3", + "jquery": "^4.0.0", "jsdoc": "^4.0.2", "jsdom": "^27.0.0", "karma": "^6.4.1", @@ -7908,9 +7908,9 @@ } }, "node_modules/jquery": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-4.0.0.tgz", + "integrity": "sha512-TXCHVR3Lb6TZdtw1l3RTLf8RBWVGexdxL6AC8/e0xZKEpBflBsjh9/8LXw+dkNFuOyW9B7iB3O1sP7hS0Kiacg==", "dev": true }, "node_modules/js-tokens": { @@ -19016,9 +19016,9 @@ } }, "jquery": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-4.0.0.tgz", + "integrity": "sha512-TXCHVR3Lb6TZdtw1l3RTLf8RBWVGexdxL6AC8/e0xZKEpBflBsjh9/8LXw+dkNFuOyW9B7iB3O1sP7hS0Kiacg==", "dev": true }, "js-tokens": { diff --git a/package.json b/package.json index afb51ce7a..c5b7c3fb0 100644 --- a/package.json +++ b/package.json @@ -156,7 +156,7 @@ "http-server": "^14.1.1", "husky": "^9.0.7", "inquirer": "^8.2.5", - "jquery": "^3.6.3", + "jquery": "^4.0.0", "jsdoc": "^4.0.2", "jsdom": "^27.0.0", "karma": "^6.4.1", From 240f8b53ad168521a63b54d0053b96ce430c7184 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Thu, 5 Feb 2026 07:58:31 -0700 Subject: [PATCH 09/32] fix(scrollable-region-focusable): do not fail scroll areas when all content is visible without scrolling (#4993) Scrollable-region-focusable-matches now tests the text rects or bounding rect of all content to see if is outside the bounding rect of the scroll container. Only then does it pass the matcher. This changed made many of the integration test cases inapplicable so I moved them to the bottom of the file to be grouped with the other inapplicable results. For the unit tests I had to pad some of the tests with more content in order for the visible content to require scrolling. Closes: https://github.com/dequelabs/axe-core/issues/4535 --- .../scrollable-region-focusable-matches.js | 40 ++++++-- .../scrollable-region-focusable.html | 95 +++++++++++++------ .../scrollable-region-focusable.json | 11 +-- .../scrollable-region-focusable-matches.js | 46 ++++++++- 4 files changed, 144 insertions(+), 48 deletions(-) diff --git a/lib/rules/scrollable-region-focusable-matches.js b/lib/rules/scrollable-region-focusable-matches.js index 34c4b08d7..9f1cad3b6 100644 --- a/lib/rules/scrollable-region-focusable-matches.js +++ b/lib/rules/scrollable-region-focusable-matches.js @@ -1,4 +1,6 @@ -import hasContentVirtual from '../commons/dom/has-content-virtual'; +import hasContentVirtual, { + hasChildTextNodes +} from '../commons/dom/has-content-virtual'; import isComboboxPopup from '../commons/aria/is-combobox-popup'; import { querySelectorAll, getScroll } from '../core/utils'; @@ -9,13 +11,39 @@ export default function scrollableRegionFocusableMatches(node, virtualNode) { // It's not a combobox popup, which commonly has keyboard focus added isComboboxPopup(virtualNode) === false && // And there's something actually worth scrolling to - isNoneEmptyElement(virtualNode) + isNonEmptyElementOutsideViewableRect(virtualNode) ); } -function isNoneEmptyElement(vNode) { - return querySelectorAll(vNode, '*').some(elm => +function isNonEmptyElementOutsideViewableRect(vNode) { + const boundingRect = vNode.boundingClientRect; + + return querySelectorAll(vNode, '*').some(elm => { // (elm, noRecursion, ignoreAria) - hasContentVirtual(elm, true, true) - ); + if (!hasContentVirtual(elm, true, true)) { + return false; + } + + let rects = []; + if (hasChildTextNodes(elm)) { + rects.push(...getContentRects(elm)); + } else { + rects = [elm.boundingClientRect]; + } + + return rects.some(rect => { + return ( + rect.left < boundingRect.left || + rect.right > boundingRect.right || + rect.top < boundingRect.top || + rect.bottom > boundingRect.bottom + ); + }); + }); +} + +function getContentRects(vNode) { + const range = document.createRange(); + range.selectNodeContents(vNode.actualNode); + return Array.from(range.getClientRects()); } diff --git a/test/integration/rules/scrollable-region-focusable/scrollable-region-focusable.html b/test/integration/rules/scrollable-region-focusable/scrollable-region-focusable.html index 750785c2b..24dfc3c0b 100644 --- a/test/integration/rules/scrollable-region-focusable/scrollable-region-focusable.html +++ b/test/integration/rules/scrollable-region-focusable/scrollable-region-focusable.html @@ -3,39 +3,13 @@ -
-
-

Content

-
-
- -
+

-
-
-

Content

-
-
- -
-
-
-
-

Content

-
-
-
-
-
@@ -47,10 +21,17 @@
-
-
-

Content

-
+
+

Contents

+

+ Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium + doloremque laudantium. +

+
+ +
+

Contents

+
@@ -144,3 +125,55 @@ test test + +
+
+

Content

+
+
+ +
+
+

Content

+
+
+ +
+
+
+
+

Content

+
+
+
+
+ +
+
+

Content

+
+
+ +
+

Contents

+
+ +
+ +
diff --git a/test/integration/rules/scrollable-region-focusable/scrollable-region-focusable.json b/test/integration/rules/scrollable-region-focusable/scrollable-region-focusable.json index 50220b0bd..e18c85ad3 100644 --- a/test/integration/rules/scrollable-region-focusable/scrollable-region-focusable.json +++ b/test/integration/rules/scrollable-region-focusable/scrollable-region-focusable.json @@ -1,13 +1,6 @@ { "description": "scrollable-region-focusable tests", "rule": "scrollable-region-focusable", - "violations": [["#fail1"], ["#fail2"], ["#fail3"]], - "passes": [ - ["#pass1"], - ["#pass2"], - ["#pass3"], - ["#pass4"], - ["#pass5"], - ["#pass6"] - ] + "violations": [["#fail1"], ["#fail2"], ["#fail3"], ["#fail4"]], + "passes": [["#pass1"], ["#pass2"]] } diff --git a/test/rule-matches/scrollable-region-focusable-matches.js b/test/rule-matches/scrollable-region-focusable-matches.js index 01dfe1771..7900610c4 100644 --- a/test/rule-matches/scrollable-region-focusable-matches.js +++ b/test/rule-matches/scrollable-region-focusable-matches.js @@ -56,7 +56,7 @@ describe('scrollable-region-focusable-matches', function () { const target = queryFixture( '
' + '
' + - '

Content

' + + '

Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium

' + '
' + '
' ); @@ -138,7 +138,49 @@ describe('scrollable-region-focusable-matches', function () { it('returns true for combobox with non-valid role', function () { const target = queryFixture( - '
  • Option
' + '
  • Option
  • Option
  • Option
  • Option
' + ); + const actual = rule.matches(target.actualNode, target); + assert.isTrue(actual); + }); + + it('returns false when all text is visible without scrolling', () => { + const target = queryFixture( + `
+

Contents

+
` + ); + const actual = rule.matches(target.actualNode, target); + assert.isFalse(actual); + }); + + it('returns false when all visible content is visible without scrolling', () => { + const target = queryFixture( + `
+ +
` + ); + const actual = rule.matches(target.actualNode, target); + assert.isFalse(actual); + }); + + it('returns true when any visible text is not visible without scrolling', () => { + const target = queryFixture( + `
+

Contents

+

Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.

+
` + ); + const actual = rule.matches(target.actualNode, target); + assert.isTrue(actual); + }); + + it('returns true when any visible content is not visible without scrolling', () => { + const target = queryFixture( + `
+

Contents

+ +
` ); const actual = rule.matches(target.actualNode, target); assert.isTrue(actual); From 91b2c28a30b8979360e923755464a20b012af718 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 10:37:27 -0700 Subject: [PATCH 10/32] chore: bump the npm-low-risk group across 1 directory with 8 updates (#5008) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the npm-low-risk group with 8 updates in the / directory: | Package | From | To | | --- | --- | --- | | [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) | `7.28.5` | `7.28.6` | | [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) | `7.28.5` | `7.28.6` | | [@babel/runtime-corejs3](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime-corejs3) | `7.28.4` | `7.28.6` | | [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) | `3.47.0` | `3.48.0` | | [globals](https://github.com/sindresorhus/globals) | `17.1.0` | `17.2.0` | | [jsdom](https://github.com/jsdom/jsdom) | `27.3.0` | `27.4.0` | | [prettier](https://github.com/prettier/prettier) | `3.7.4` | `3.8.1` | | [selenium-webdriver](https://github.com/SeleniumHQ/selenium) | `4.39.0` | `4.40.0` | Updates `@babel/core` from 7.28.5 to 7.28.6
Release notes

Sourced from @​babel/core's releases.

v7.28.6 (2026-01-12)

Thanks @​kadhirash and @​kolvian for your first PRs!

:bug: Bug Fix

  • babel-cli, babel-code-frame, babel-core, babel-helper-check-duplicate-nodes, babel-helper-fixtures, babel-helper-plugin-utils, babel-node, babel-plugin-transform-flow-comments, babel-plugin-transform-modules-commonjs, babel-plugin-transform-property-mutators, babel-preset-env, babel-traverse, babel-types
  • babel-plugin-transform-regenerator
  • babel-plugin-transform-react-jsx

:nail_care: Polish

  • babel-core, babel-standalone

:house: Internal

  • babel-plugin-bugfix-v8-static-class-fields-redefine-readonly, babel-plugin-proposal-decorators, babel-plugin-proposal-import-attributes-to-assertions, babel-plugin-proposal-import-wasm-source, babel-plugin-syntax-async-do-expressions, babel-plugin-syntax-decorators, babel-plugin-syntax-destructuring-private, babel-plugin-syntax-do-expressions, babel-plugin-syntax-explicit-resource-management, babel-plugin-syntax-export-default-from, babel-plugin-syntax-flow, babel-plugin-syntax-function-bind, babel-plugin-syntax-function-sent, babel-plugin-syntax-import-assertions, babel-plugin-syntax-import-attributes, babel-plugin-syntax-import-defer, babel-plugin-syntax-import-source, babel-plugin-syntax-jsx, babel-plugin-syntax-module-blocks, babel-plugin-syntax-optional-chaining-assign, babel-plugin-syntax-partial-application, babel-plugin-syntax-pipeline-operator, babel-plugin-syntax-throw-expressions, babel-plugin-syntax-typescript, babel-plugin-transform-async-generator-functions, babel-plugin-transform-async-to-generator, babel-plugin-transform-class-properties, babel-plugin-transform-class-static-block, babel-plugin-transform-dotall-regex, babel-plugin-transform-duplicate-named-capturing-groups-regex, babel-plugin-transform-explicit-resource-management, babel-plugin-transform-exponentiation-operator, babel-plugin-transform-json-strings, babel-plugin-transform-logical-assignment-operators, babel-plugin-transform-nullish-coalescing-operator, babel-plugin-transform-numeric-separator, babel-plugin-transform-object-rest-spread, babel-plugin-transform-optional-catch-binding, babel-plugin-transform-optional-chaining, babel-plugin-transform-private-methods, babel-plugin-transform-private-property-in-object, babel-plugin-transform-regexp-modifiers, babel-plugin-transform-unicode-property-regex, babel-plugin-transform-unicode-sets-regex

:running_woman: Performance

  • babel-plugin-transform-react-jsx

Committers: 7

Commits

Updates `@babel/preset-env` from 7.28.5 to 7.28.6
Release notes

Sourced from @​babel/preset-env's releases.

v7.28.6 (2026-01-12)

Thanks @​kadhirash and @​kolvian for your first PRs!

:bug: Bug Fix

  • babel-cli, babel-code-frame, babel-core, babel-helper-check-duplicate-nodes, babel-helper-fixtures, babel-helper-plugin-utils, babel-node, babel-plugin-transform-flow-comments, babel-plugin-transform-modules-commonjs, babel-plugin-transform-property-mutators, babel-preset-env, babel-traverse, babel-types
  • babel-plugin-transform-regenerator
  • babel-plugin-transform-react-jsx

:nail_care: Polish

  • babel-core, babel-standalone

:house: Internal

  • babel-plugin-bugfix-v8-static-class-fields-redefine-readonly, babel-plugin-proposal-decorators, babel-plugin-proposal-import-attributes-to-assertions, babel-plugin-proposal-import-wasm-source, babel-plugin-syntax-async-do-expressions, babel-plugin-syntax-decorators, babel-plugin-syntax-destructuring-private, babel-plugin-syntax-do-expressions, babel-plugin-syntax-explicit-resource-management, babel-plugin-syntax-export-default-from, babel-plugin-syntax-flow, babel-plugin-syntax-function-bind, babel-plugin-syntax-function-sent, babel-plugin-syntax-import-assertions, babel-plugin-syntax-import-attributes, babel-plugin-syntax-import-defer, babel-plugin-syntax-import-source, babel-plugin-syntax-jsx, babel-plugin-syntax-module-blocks, babel-plugin-syntax-optional-chaining-assign, babel-plugin-syntax-partial-application, babel-plugin-syntax-pipeline-operator, babel-plugin-syntax-throw-expressions, babel-plugin-syntax-typescript, babel-plugin-transform-async-generator-functions, babel-plugin-transform-async-to-generator, babel-plugin-transform-class-properties, babel-plugin-transform-class-static-block, babel-plugin-transform-dotall-regex, babel-plugin-transform-duplicate-named-capturing-groups-regex, babel-plugin-transform-explicit-resource-management, babel-plugin-transform-exponentiation-operator, babel-plugin-transform-json-strings, babel-plugin-transform-logical-assignment-operators, babel-plugin-transform-nullish-coalescing-operator, babel-plugin-transform-numeric-separator, babel-plugin-transform-object-rest-spread, babel-plugin-transform-optional-catch-binding, babel-plugin-transform-optional-chaining, babel-plugin-transform-private-methods, babel-plugin-transform-private-property-in-object, babel-plugin-transform-regexp-modifiers, babel-plugin-transform-unicode-property-regex, babel-plugin-transform-unicode-sets-regex

:running_woman: Performance

  • babel-plugin-transform-react-jsx

Committers: 7

Commits

Updates `@babel/runtime-corejs3` from 7.28.4 to 7.28.6
Release notes

Sourced from @​babel/runtime-corejs3's releases.

v7.28.6 (2026-01-12)

Thanks @​kadhirash and @​kolvian for your first PRs!

:bug: Bug Fix

  • babel-cli, babel-code-frame, babel-core, babel-helper-check-duplicate-nodes, babel-helper-fixtures, babel-helper-plugin-utils, babel-node, babel-plugin-transform-flow-comments, babel-plugin-transform-modules-commonjs, babel-plugin-transform-property-mutators, babel-preset-env, babel-traverse, babel-types
  • babel-plugin-transform-regenerator
  • babel-plugin-transform-react-jsx

:nail_care: Polish

  • babel-core, babel-standalone

:house: Internal

  • babel-plugin-bugfix-v8-static-class-fields-redefine-readonly, babel-plugin-proposal-decorators, babel-plugin-proposal-import-attributes-to-assertions, babel-plugin-proposal-import-wasm-source, babel-plugin-syntax-async-do-expressions, babel-plugin-syntax-decorators, babel-plugin-syntax-destructuring-private, babel-plugin-syntax-do-expressions, babel-plugin-syntax-explicit-resource-management, babel-plugin-syntax-export-default-from, babel-plugin-syntax-flow, babel-plugin-syntax-function-bind, babel-plugin-syntax-function-sent, babel-plugin-syntax-import-assertions, babel-plugin-syntax-import-attributes, babel-plugin-syntax-import-defer, babel-plugin-syntax-import-source, babel-plugin-syntax-jsx, babel-plugin-syntax-module-blocks, babel-plugin-syntax-optional-chaining-assign, babel-plugin-syntax-partial-application, babel-plugin-syntax-pipeline-operator, babel-plugin-syntax-throw-expressions, babel-plugin-syntax-typescript, babel-plugin-transform-async-generator-functions, babel-plugin-transform-async-to-generator, babel-plugin-transform-class-properties, babel-plugin-transform-class-static-block, babel-plugin-transform-dotall-regex, babel-plugin-transform-duplicate-named-capturing-groups-regex, babel-plugin-transform-explicit-resource-management, babel-plugin-transform-exponentiation-operator, babel-plugin-transform-json-strings, babel-plugin-transform-logical-assignment-operators, babel-plugin-transform-nullish-coalescing-operator, babel-plugin-transform-numeric-separator, babel-plugin-transform-object-rest-spread, babel-plugin-transform-optional-catch-binding, babel-plugin-transform-optional-chaining, babel-plugin-transform-private-methods, babel-plugin-transform-private-property-in-object, babel-plugin-transform-regexp-modifiers, babel-plugin-transform-unicode-property-regex, babel-plugin-transform-unicode-sets-regex

:running_woman: Performance

  • babel-plugin-transform-react-jsx

Committers: 7

v7.28.5 (2025-10-23)

Thank you @​CO0Ki3, @​Olexandr88, and @​youthfulhps for your first PRs!

:eyeglasses: Spec Compliance

:bug: Bug Fix

  • babel-plugin-proposal-destructuring-private
  • babel-parser
  • babel-plugin-proposal-discard-binding, babel-plugin-transform-destructuring

... (truncated)

Commits
Maintainer changes

This version was pushed to npm by [GitHub Actions](https://www.npmjs.com/~GitHub Actions), a new releaser for @​babel/runtime-corejs3 since your current version.


Updates `core-js` from 3.47.0 to 3.48.0
Changelog

Sourced from core-js's changelog.

3.48.0 - 2026.01.21

  • Changes v3.47.0...v3.48.0 (126 commits)
  • Map upsert proposal:
    • Built-ins:
      • Map.prototype.getOrInsert
      • Map.prototype.getOrInsertComputed
      • WeakMap.prototype.getOrInsert
      • WeakMap.prototype.getOrInsertComputed
    • Moved to stable ES, January 2026 TC39 meeting
    • Added es. namespace modules, /es/ and /stable/ namespaces entries
  • Use CreateDataProperty / CreateDataPropertyOrThrow in some missed cases, #1497
  • Minor fix / optimization in the RegExp constructor (NCG and dotAll) polyfill
  • Added some more workarounds for a Safari < 13 bug with silent ignore of non-writable array .length
  • Added detection of a Webkit bug: Iterator.prototype.flatMap throws on iterator without return method
  • Added detection of a V8 ~ Chromium < 144 bug: Uint8Array.prototype.setFromHex throws an error on length-tracking views over ResizableArrayBuffer
  • Compat data improvements:
Commits
  • 5d657da v3.48.0
  • 5644e73 Add bug detection for Uint8Array.prototype.setFromHex
  • 804a10e Merge pull request #1501 from zloirock/flat-map-fix
  • 45d7fe3 Add bug detection to Iterator flatMap method
  • efd9c2f move Map upsert proposal to stable ES
  • dcb938d update the year and normalize the copyright wording
  • 5454a5d add some more workarounds for a Safari < 13 bug with silent ignore of non-wri...
  • 73d4b6c add some more createProperty cases
  • 9c89290 fix: spec compliance for Array.prototype.flat and flatMap
  • e3774ce fix: use createProperty in Array.prototype.filter
  • Additional commits viewable in compare view

Updates `globals` from 17.1.0 to 17.2.0
Release notes

Sourced from globals's releases.

v17.2.0

  • jasmine: Add throwUnless and throwUnlessAsync globals (#335) 97f23a7

https://github.com/sindresorhus/globals/compare/v17.1.0...v17.2.0

Commits

Updates `jsdom` from 27.3.0 to 27.4.0
Release notes

Sourced from jsdom's releases.

Version 27.4.0

  • Added TextEncoder and TextDecoder.
  • Improved decoding of HTML bytes by using the new @exodus/bytes package; it is now much more correct. (ChALkeR)
  • Improved decoding of XML bytes to use UTF-8 more often, instead of sniffing for <meta charset> or using the parent frame's encoding.
  • Fixed a memory leak when Ranges were used and then the elements referred to by those ranges were removed.
Changelog

Sourced from jsdom's changelog.

27.4.0

  • Added TextEncoder and TextDecoder.
  • Improved decoding of HTML bytes by using the new @exodus/bytes package; it is now much more correct. (ChALkeR)
  • Improved decoding of XML bytes to use UTF-8 more often, instead of sniffing for <meta charset> or using the parent frame's encoding.
  • Fixed a memory leak when Ranges were used and then the elements referred to by those ranges were removed.
Commits
  • 098d16d Version 27.4.0
  • 1cd029e Improve asciiLowercase/asciiUppercase performance
  • 83fcb62 Implement TextEncoder and TextDecoder; improve XML decoding
  • ddad97d Switch from iconv-lite to exodus/bytes for decoding
  • 25cb2a1 Use weak references for ranges
  • ed4f5ed Add currently-failing CSS regression tests
  • See full diff in compare view

Updates `prettier` from 3.7.4 to 3.8.1
Release notes

Sourced from prettier's releases.

3.8.1

🔗 Changelog

3.8.0

  • Support Angular v21.1

diff

🔗 Release note "Prettier 3.8: Support for Angular v21.1"

Changelog

Sourced from prettier's changelog.

3.8.1

diff

Include available printers in plugin type declarations (#18706 by @​porada)

// Input
import * as prettierPluginEstree from
"prettier/plugins/estree";

// Prettier 3.8.0 // Property 'printers' does not exist on type 'typeof import("prettier/plugins/estree")'. ts(2339) prettierPluginEstree.printers.estree; //=> any

// Prettier 3.8.1 prettierPluginEstree.printers.estree; //=> Printer prettierPluginEstree.printers["estree-json"]; //=> Printer

3.8.0

diff

🔗 Release Notes

Commits

Updates `selenium-webdriver` from 4.39.0 to 4.40.0
Release notes

Sourced from selenium-webdriver's releases.

Selenium 4.40.0

Detailed Changelogs by Component

Java     |     Python     |     DotNet     |     Ruby     |     JavaScript

What's Changed

... (truncated)

Commits
  • b3333f1 [build] Prepare for release of Selenium 4.40 (#16931)
  • 1229133 [build] manual trigger job needs an approval step to limit
  • 1cc4bc7 [build] remove ruby remote tests from CI
  • bcd0976 [build] use rulesets to restrict and unrestrict trunk during release window (...
  • 47dbd0d [dotnet] [bidi] Expose Input module in root BiDi class (#16940)
  • 1fefb89 [dotnet] [bidi] FileDialogOpened event in Input module (#16934)
  • 691fb1c [grid] Improve race conditions in Grid session distribution (#16939)
  • aaeb4a5 [build] ensure compatible edge browser and driver when pinning
  • 492b6c4 [dotnet] fix syntax issue with bazel target preventing build
  • 631c5b0 [java] sanitize descriptions before using them in JavaDoc comments
  • Additional commits viewable in compare view

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-automerge-start) [//]: # (dependabot-automerge-end) ---
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 merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 1368 +++++++++++++++++++++------------------------ 1 file changed, 651 insertions(+), 717 deletions(-) diff --git a/package-lock.json b/package-lock.json index e8f8aa471..6e7580ca7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -161,13 +161,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -176,29 +175,29 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -215,13 +214,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", + "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", "dev": true, "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -243,13 +242,12 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -275,17 +273,17 @@ "dev": true }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", - "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.3", + "@babel/traverse": "^7.28.6", "semver": "^6.3.1" }, "engines": { @@ -296,14 +294,13 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", - "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "regexpu-core": "^6.2.0", + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "engines": { @@ -362,42 +359,40 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", - "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -420,11 +415,10 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -434,7 +428,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", @@ -448,15 +441,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -509,40 +501,39 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", - "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", + "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/template": "^7.27.1", - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "dev": true, "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -618,13 +609,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", - "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", + "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -665,13 +656,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", + "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -681,13 +671,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -741,14 +730,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", + "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.29.0" }, "engines": { "node": ">=6.9.0" @@ -758,14 +747,13 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "engines": { @@ -792,12 +780,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", - "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", + "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -807,14 +795,13 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -824,13 +811,13 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", - "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", + "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -840,17 +827,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", + "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -860,14 +847,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", + "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/template": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -893,14 +879,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", + "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -926,14 +911,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -959,13 +943,13 @@ } }, "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", + "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -975,12 +959,12 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", - "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", + "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1041,13 +1025,12 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", + "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1073,12 +1056,12 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", - "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", + "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1121,14 +1104,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1206,13 +1188,12 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", + "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1222,13 +1203,12 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", + "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1238,16 +1218,16 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", - "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", + "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.4" + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1274,13 +1254,12 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", + "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1290,12 +1269,12 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", - "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", + "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { @@ -1321,14 +1300,13 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", + "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1338,15 +1316,14 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", + "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1372,12 +1349,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", - "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", + "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1387,14 +1364,13 @@ } }, "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", + "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1436,13 +1412,12 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", + "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { @@ -1517,14 +1492,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", + "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1551,14 +1525,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", + "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1568,75 +1541,75 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", - "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.6.tgz", + "integrity": "sha512-GaTI4nXDrs7l0qaJ6Rg06dtOXTBCG6TMDB44zbqofCIC4PqC7SEvmFFtpxzCDw9W5aJ7RKVshgXTLvLdBFV/qw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/compat-data": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-import-assertions": "^7.28.6", + "@babel/plugin-syntax-import-attributes": "^7.28.6", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.6", + "@babel/plugin-transform-async-to-generator": "^7.28.6", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.5", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.4", - "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.6", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-class-static-block": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-computed-properties": "^7.28.6", "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-dotall-regex": "^7.28.6", "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.28.6", "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.28.5", + "@babel/plugin-transform-explicit-resource-management": "^7.28.6", + "@babel/plugin-transform-exponentiation-operator": "^7.28.6", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.28.6", "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.28.6", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.4", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-numeric-separator": "^7.28.6", + "@babel/plugin-transform-object-rest-spread": "^7.28.6", "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.28.5", + "@babel/plugin-transform-optional-catch-binding": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.28.6", + "@babel/plugin-transform-private-property-in-object": "^7.28.6", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.4", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.6", + "@babel/plugin-transform-regexp-modifiers": "^7.28.6", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-spread": "^7.28.6", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.28.6", "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", @@ -1666,9 +1639,9 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.4.tgz", - "integrity": "sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.6.tgz", + "integrity": "sha512-kz2fAQ5UzjV7X7D3ySxmj3vRq89dTpqOZWv76Z6pNPztkwb/0Yj1Mtx1xFrYj6mbIHysxtBot8J4o0JLCblcFw==", "dev": true, "dependencies": { "core-js-pure": "^3.43.0" @@ -1678,32 +1651,31 @@ } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -1711,9 +1683,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -2015,6 +1987,23 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@exodus/bytes": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.11.0.tgz", + "integrity": "sha512-wO3vd8nsEHdumsXrjGO/v4p6irbg7hy9kvIeR6i2AwylZSk4HJdWgL0FNaVquW1+AweJcdvU1IEpuIWk/WaPnA==", + "dev": true, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, "node_modules/@hapi/address": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-5.1.1.tgz", @@ -4234,9 +4223,9 @@ } }, "node_modules/core-js": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz", - "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", + "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", "dev": true, "hasInstallScript": true, "funding": { @@ -6376,9 +6365,9 @@ } }, "node_modules/globals": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.1.0.tgz", - "integrity": "sha512-8HoIcWI5fCvG5NADj4bDav+er9B9JMj2vyL2pI8D0eismKyUvPLTSs+Ln3wqhwcp306i73iyVnEKx3F6T47TGw==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.2.0.tgz", + "integrity": "sha512-tovnCz/fEq+Ripoq+p/gN1u7l6A7wwkoBT9pRCzTHzsD/LvADIzXZdjmRymh5Ztf0DYC3Rwg5cZRYjxzBmzbWg==", "dev": true, "engines": { "node": ">=18" @@ -7985,17 +7974,18 @@ } }, "node_modules/jsdom": { - "version": "27.3.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.3.0.tgz", - "integrity": "sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==", + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.4.0.tgz", + "integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==", "dev": true, "dependencies": { "@acemir/cssom": "^0.9.28", "@asamuzakjp/dom-selector": "^6.7.6", + "@exodus/bytes": "^1.6.0", "cssstyle": "^5.3.4", "data-urls": "^6.0.0", "decimal.js": "^10.6.0", - "html-encoding-sniffer": "^4.0.0", + "html-encoding-sniffer": "^6.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", @@ -8005,7 +7995,6 @@ "tough-cookie": "^6.0.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.0", - "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^15.1.0", "ws": "^8.18.3", @@ -8024,39 +8013,15 @@ } }, "node_modules/jsdom/node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^3.1.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/jsdom/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jsdom/node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", "dev": true, "dependencies": { - "iconv-lite": "0.6.3" + "@exodus/bytes": "^1.6.0" }, "engines": { - "node": ">=18" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/jsesc": { @@ -10595,9 +10560,9 @@ } }, "node_modules/prettier": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", - "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -11064,9 +11029,9 @@ "dev": true }, "node_modules/regenerate-unicode-properties": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", - "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", "dev": true, "dependencies": { "regenerate": "^1.4.2" @@ -11093,17 +11058,17 @@ } }, "node_modules/regexpu-core": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", - "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", "dev": true, "dependencies": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.0", + "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", - "regjsparser": "^0.12.0", + "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" + "unicode-match-property-value-ecmascript": "^2.2.1" }, "engines": { "node": ">=4" @@ -11116,29 +11081,17 @@ "dev": true }, "node_modules/regjsparser": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", - "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", "dev": true, "dependencies": { - "jsesc": "~3.0.2" + "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", @@ -11366,9 +11319,9 @@ "dev": true }, "node_modules/selenium-webdriver": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.39.0.tgz", - "integrity": "sha512-NAs9jCU+UeZ/ZmRb8R6zOp7N8eMklefdBYASnaRmCNXdgFE8w3OCxxZmLixkwqnGDHY5VF7hCulfw1Mls43N/A==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.40.0.tgz", + "integrity": "sha512-dU0QbnVKdPmoNP8OtMCazRdtU2Ux6Wl4FEpG1iwUbDeajJK1dBAywBLrC1D7YFRtogHzN96AbXBgBAJaarcysw==", "dev": true, "funding": [ { @@ -12695,18 +12648,18 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", - "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", "dev": true, "engines": { "node": ">=4" @@ -13418,37 +13371,37 @@ } }, "@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "dev": true }, "@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -13458,13 +13411,13 @@ } }, "@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", + "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", "dev": true, "requires": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -13480,12 +13433,12 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "requires": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -13510,28 +13463,28 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", - "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.3", + "@babel/traverse": "^7.28.6", "semver": "^6.3.1" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", - "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "regexpu-core": "^6.2.0", + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", "semver": "^6.3.1" } }, @@ -13572,34 +13525,34 @@ "dev": true }, "@babel/helper-member-expression-to-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", - "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", "dev": true, "requires": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" } }, "@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "requires": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" } }, "@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" } }, "@babel/helper-optimise-call-expression": { @@ -13612,9 +13565,9 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true }, "@babel/helper-remap-async-to-generator": { @@ -13629,14 +13582,14 @@ } }, "@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.6" } }, "@babel/helper-skip-transparent-expression-wrappers": { @@ -13668,33 +13621,33 @@ "dev": true }, "@babel/helper-wrap-function": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", - "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", + "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", "dev": true, "requires": { - "@babel/template": "^7.27.1", - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" } }, "@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "requires": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" } }, "@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "dev": true, "requires": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.29.0" } }, "@babel/plugin-bugfix-firefox-class-in-computed-class-key": { @@ -13737,13 +13690,13 @@ } }, "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", - "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", + "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/traverse": "^7.28.6" } }, "@babel/plugin-proposal-object-rest-spread": { @@ -13767,21 +13720,21 @@ "requires": {} }, "@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", + "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-syntax-object-rest-spread": { @@ -13813,24 +13766,24 @@ } }, "@babel/plugin-transform-async-generator-functions": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", + "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.29.0" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1" } }, @@ -13844,56 +13797,56 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", - "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", + "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-class-static-block": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", - "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", + "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", + "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/traverse": "^7.28.6" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", + "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/template": "^7.28.6" } }, "@babel/plugin-transform-destructuring": { @@ -13907,13 +13860,13 @@ } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", + "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-duplicate-keys": { @@ -13926,13 +13879,13 @@ } }, "@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-dynamic-import": { @@ -13945,22 +13898,22 @@ } }, "@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", + "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", - "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", + "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-export-namespace-from": { @@ -13994,12 +13947,12 @@ } }, "@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", + "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-literals": { @@ -14012,12 +13965,12 @@ } }, "@babel/plugin-transform-logical-assignment-operators": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", - "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", + "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-member-expression-literals": { @@ -14040,13 +13993,13 @@ } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-modules-systemjs": { @@ -14091,34 +14044,34 @@ } }, "@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", + "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", + "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-object-rest-spread": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", - "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", + "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", "dev": true, "requires": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.4" + "@babel/traverse": "^7.28.6" } }, "@babel/plugin-transform-object-super": { @@ -14132,21 +14085,21 @@ } }, "@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", + "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-optional-chaining": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", - "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", + "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" } }, @@ -14160,24 +14113,24 @@ } }, "@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", + "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", + "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-property-literals": { @@ -14190,22 +14143,22 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", - "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", + "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", + "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-reserved-words": { @@ -14227,12 +14180,12 @@ } }, "@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", + "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" } }, @@ -14273,13 +14226,13 @@ } }, "@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", + "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-unicode-regex": { @@ -14293,85 +14246,85 @@ } }, "@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", + "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/preset-env": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", - "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.6.tgz", + "integrity": "sha512-GaTI4nXDrs7l0qaJ6Rg06dtOXTBCG6TMDB44zbqofCIC4PqC7SEvmFFtpxzCDw9W5aJ7RKVshgXTLvLdBFV/qw==", "dev": true, "requires": { - "@babel/compat-data": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/compat-data": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-import-assertions": "^7.28.6", + "@babel/plugin-syntax-import-attributes": "^7.28.6", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.6", + "@babel/plugin-transform-async-to-generator": "^7.28.6", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.5", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.4", - "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.6", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-class-static-block": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-computed-properties": "^7.28.6", "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-dotall-regex": "^7.28.6", "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.28.6", "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.28.5", + "@babel/plugin-transform-explicit-resource-management": "^7.28.6", + "@babel/plugin-transform-exponentiation-operator": "^7.28.6", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.28.6", "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.28.6", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.4", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-numeric-separator": "^7.28.6", + "@babel/plugin-transform-object-rest-spread": "^7.28.6", "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.28.5", + "@babel/plugin-transform-optional-catch-binding": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.28.6", + "@babel/plugin-transform-private-property-in-object": "^7.28.6", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.4", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.6", + "@babel/plugin-transform-regexp-modifiers": "^7.28.6", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-spread": "^7.28.6", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.28.6", "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", @@ -14392,44 +14345,44 @@ } }, "@babel/runtime-corejs3": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.4.tgz", - "integrity": "sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.6.tgz", + "integrity": "sha512-kz2fAQ5UzjV7X7D3ySxmj3vRq89dTpqOZWv76Z6pNPztkwb/0Yj1Mtx1xFrYj6mbIHysxtBot8J4o0JLCblcFw==", "dev": true, "requires": { "core-js-pure": "^3.43.0" } }, "@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" } }, "@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.27.1", @@ -14587,6 +14540,13 @@ "levn": "^0.4.1" } }, + "@exodus/bytes": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.11.0.tgz", + "integrity": "sha512-wO3vd8nsEHdumsXrjGO/v4p6irbg7hy9kvIeR6i2AwylZSk4HJdWgL0FNaVquW1+AweJcdvU1IEpuIWk/WaPnA==", + "dev": true, + "requires": {} + }, "@hapi/address": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-5.1.1.tgz", @@ -16321,9 +16281,9 @@ "dev": true }, "core-js": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz", - "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", + "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", "dev": true }, "core-js-compat": { @@ -17922,9 +17882,9 @@ } }, "globals": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.1.0.tgz", - "integrity": "sha512-8HoIcWI5fCvG5NADj4bDav+er9B9JMj2vyL2pI8D0eismKyUvPLTSs+Ln3wqhwcp306i73iyVnEKx3F6T47TGw==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.2.0.tgz", + "integrity": "sha512-tovnCz/fEq+Ripoq+p/gN1u7l6A7wwkoBT9pRCzTHzsD/LvADIzXZdjmRymh5Ztf0DYC3Rwg5cZRYjxzBmzbWg==", "dev": true }, "globule": { @@ -19083,17 +19043,18 @@ } }, "jsdom": { - "version": "27.3.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.3.0.tgz", - "integrity": "sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==", + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.4.0.tgz", + "integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==", "dev": true, "requires": { "@acemir/cssom": "^0.9.28", "@asamuzakjp/dom-selector": "^6.7.6", + "@exodus/bytes": "^1.6.0", "cssstyle": "^5.3.4", "data-urls": "^6.0.0", "decimal.js": "^10.6.0", - "html-encoding-sniffer": "^4.0.0", + "html-encoding-sniffer": "^6.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", @@ -19103,7 +19064,6 @@ "tough-cookie": "^6.0.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.0", - "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^15.1.0", "ws": "^8.18.3", @@ -19111,30 +19071,12 @@ }, "dependencies": { "html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", "dev": true, "requires": { - "whatwg-encoding": "^3.1.1" - } - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "dev": true, - "requires": { - "iconv-lite": "0.6.3" + "@exodus/bytes": "^1.6.0" } } } @@ -21046,9 +20988,9 @@ "dev": true }, "prettier": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", - "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true }, "pretty-bytes": { @@ -21406,9 +21348,9 @@ "dev": true }, "regenerate-unicode-properties": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", - "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", "dev": true, "requires": { "regenerate": "^1.4.2" @@ -21426,17 +21368,17 @@ } }, "regexpu-core": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", - "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", "dev": true, "requires": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.0", + "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", - "regjsparser": "^0.12.0", + "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" + "unicode-match-property-value-ecmascript": "^2.2.1" } }, "regjsgen": { @@ -21446,20 +21388,12 @@ "dev": true }, "regjsparser": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", - "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", "dev": true, "requires": { - "jsesc": "~3.0.2" - }, - "dependencies": { - "jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true - } + "jsesc": "~3.1.0" } }, "relateurl": { @@ -21635,9 +21569,9 @@ "dev": true }, "selenium-webdriver": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.39.0.tgz", - "integrity": "sha512-NAs9jCU+UeZ/ZmRb8R6zOp7N8eMklefdBYASnaRmCNXdgFE8w3OCxxZmLixkwqnGDHY5VF7hCulfw1Mls43N/A==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.40.0.tgz", + "integrity": "sha512-dU0QbnVKdPmoNP8OtMCazRdtU2Ux6Wl4FEpG1iwUbDeajJK1dBAywBLrC1D7YFRtogHzN96AbXBgBAJaarcysw==", "dev": true, "requires": { "@bazel/runfiles": "^6.5.0", @@ -22646,15 +22580,15 @@ } }, "unicode-match-property-value-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", - "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", "dev": true }, "unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", "dev": true }, "union": { From 88bc57fd3de12cd69d365b3f385ce9a2e30b7bd5 Mon Sep 17 00:00:00 2001 From: Wilco Fiers Date: Wed, 18 Feb 2026 12:46:32 +0100 Subject: [PATCH 11/32] fix(DqElement): avoid calling constructors with cloneNode (#5013) Closes: https://github.com/dequelabs/axe-core/issues/4996 - **Avoid calling cloneNode when retrieving source** - Add a new utils.getElementSource (which works even if the tree is not constructed - Made sure getElementSource works with namespaces and non-node elements - Check each attribute if it fits in the truncated source, instead of stopping at the first that doesn't fit --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- axe.d.ts | 4 + lib/core/utils/dq-element.js | 92 +--------- lib/core/utils/get-element-source.js | 101 +++++++++++ lib/core/utils/index.js | 1 + test/core/utils/dq-element.js | 90 ---------- test/core/utils/get-element-source.js | 233 ++++++++++++++++++++++++++ 6 files changed, 340 insertions(+), 181 deletions(-) create mode 100644 lib/core/utils/get-element-source.js create mode 100644 test/core/utils/get-element-source.js diff --git a/axe.d.ts b/axe.d.ts index 786b30a23..03cd835b3 100644 --- a/axe.d.ts +++ b/axe.d.ts @@ -467,6 +467,10 @@ declare namespace axe { } interface Utils { + getElementSource: ( + element: Node | null | undefined, + options?: { maxLength?: number; attrLimit?: number } + ) => string; getFrameContexts: ( context?: ElementContext, options?: RunOptions diff --git a/lib/core/utils/dq-element.js b/lib/core/utils/dq-element.js index 556d625aa..de6480ebf 100644 --- a/lib/core/utils/dq-element.js +++ b/lib/core/utils/dq-element.js @@ -5,100 +5,10 @@ import getNodeFromTree from './get-node-from-tree'; import AbstractVirtualNode from '../base/virtual-node/abstract-virtual-node'; import cache from '../base/cache'; import memoize from './memoize'; -import getNodeAttributes from './get-node-attributes'; -import VirtualNode from '../../core/base/virtual-node/virtual-node'; +import getSource from './get-element-source'; const CACHE_KEY = 'DqElm.RunOptions'; -function getOuterHtml(element) { - let source = element.outerHTML; - - if (!source && typeof window.XMLSerializer === 'function') { - source = new window.XMLSerializer().serializeToString(element); - } - - return source || ''; -} - -/** - * Truncates the outerHTML property of an element - * @param {Node} element the element node which needs to be truncated - */ - -export function truncateElement(element) { - const maxLen = 300; - const maxAttrNameOrValueLen = 20; - - const deepStr = getOuterHtml(element); - let vNode = getNodeFromTree(element); - if (!vNode) { - vNode = new VirtualNode(element); - } - const { nodeName } = vNode.props; - - if (deepStr.length < maxLen) { - return deepStr; - } - - const attributeStrList = []; - const shallowNode = element.cloneNode(false); - const elementNodeMap = getNodeAttributes(shallowNode); - - let str = getOuterHtml(shallowNode); - - if (str.length < maxLen) { - let attrString = ''; - for (const { name, value } of elementNodeMap) { - const attr = { name, value }; - attrString += ` ${attr.name}="${attr.value}"`; - } - - str = `<${nodeName}${attrString}>`; - return str; - } - let strLen = `<${nodeName}>`.length; - - for (const { name, value } of elementNodeMap) { - if (strLen > maxLen) { - break; - } - - const attr = { name, value }; - let attrName = attr.name; - let attrValue = attr.value; - - attrName = - attrName.length > maxAttrNameOrValueLen - ? attrName.substring(0, maxAttrNameOrValueLen) + '...' - : attrName; - attrValue = - attrValue.length > maxAttrNameOrValueLen - ? attrValue.substring(0, maxAttrNameOrValueLen) + '...' - : attrValue; - - const strAttr = `${attrName}="${attrValue}"`; - strLen += (' ' + strAttr).length; - attributeStrList.push(strAttr); - } - - str = `<${nodeName} ${attributeStrList.join(' ')}>`; - if (str.length > maxLen) { - str = str.substring(0, maxLen) + ' ...>'; - } else if (attributeStrList.length < elementNodeMap.length) { - str = str.substring(0, str.length - 1) + ' ...>'; - } - - return str; -} - -function getSource(element) { - if (!element) { - return ''; - } - - return truncateElement(element); -} - /** * "Serialized" `HTMLElement`. It will calculate the CSS selector, * grab the source (outerHTML) and offer an array for storing frame paths diff --git a/lib/core/utils/get-element-source.js b/lib/core/utils/get-element-source.js new file mode 100644 index 000000000..b30354c36 --- /dev/null +++ b/lib/core/utils/get-element-source.js @@ -0,0 +1,101 @@ +import getNodeAttributes from './get-node-attributes'; +import isXHTML from './is-xhtml'; + +/** + * Gets the truncated HTML source of an element, or nodeValue for non-element nodes + * @param {Node} node the DOM node (element, text, comment, etc.) + * @param {Object} options truncation options + * @param {Number} [options.maxLength=300] maximum length of the output + * @param {Number} [options.attrLimit=20] maximum length for attribute names and values + * @returns {String} The outerHTML, truncated representation, or nodeValue for non-elements + */ +export default function getElementSource( + node, + { maxLength = 300, attrLimit = 20 } = {} +) { + if (!node) { + return ''; + } + // non-element nodes + if (node.nodeType !== 1) { + const value = node.nodeValue ?? ''; + return truncate(value, maxLength); + } + + const deepStr = getOuterHtml(node); + if (deepStr.length > maxLength) { + return getTruncatedElementSource(node, { maxLength, attrLimit }); + } + + return deepStr; +} + +/** + * Gets the outerHTML of an element, using XMLSerializer as fallback for SVG/MathML + * @param {Element} element the DOM element + * @returns {String} The serialized HTML or empty string + */ +function getOuterHtml(element) { + let source = element.outerHTML; + if (!source && typeof window.XMLSerializer === 'function') { + source = new window.XMLSerializer().serializeToString(element); + } + return source || ''; +} + +/** + * Builds a truncated HTML representation of an element when outerHTML exceeds maxLength. + * Note: attribute order may differ from the original source as node.attributes order is not guaranteed. + * @param {Element} elm the DOM element + * @param {Object} options truncation options + * @param {Number} options.maxLength maximum length of the output + * @param {Number} options.attrLimit maximum length for attribute names and values + * @returns {String} Truncated opening tag (e.g. '
') + */ +function getTruncatedElementSource(elm, { maxLength, attrLimit }) { + const nodeName = isXHTML(elm.ownerDocument || document) + ? elm.nodeName + : elm.nodeName.toLowerCase(); + + // Get a mutable attribute map, and work out their rendered length + const nodeAttrs = Array.from(getNodeAttributes(elm)).map( + ({ name, value }) => ({ name, value }) + ); + const attrsLength = nodeAttrs.reduce((acc, { name, value }) => { + // 4 = space before name + equals sign + opening quote + closing quote + return acc + name.length + value.length + 4; + }, 0); + + // 2 = opening "<" + space before first attribute + if (2 + nodeName.length + attrsLength > maxLength) { + nodeAttrs.forEach(attr => { + attr.name = truncate(attr.name, attrLimit); + attr.value = truncate(attr.value, attrLimit); + }); + } + + let source = `<${nodeName}`; + let tagEnd = '>'; + const truncateEnd = ' ...>'; + // Must check every attribute: an attr that doesn't fit may be followed by one that does + for (const attr of nodeAttrs) { + const attrStr = ` ${attr.name}="${attr.value}"`; + if (source.length + attrStr.length > maxLength - truncateEnd.length) { + tagEnd = truncateEnd; + continue; + } + source += attrStr; + } + + return source + tagEnd; +} + +/** + * Truncates a string to max length, appending '...' when truncated + * @param {String} str the string to truncate + * @param {Number} attrLimit maximum length before truncation + * @returns {String} The original string or truncated version with '...' suffix + */ +function truncate(str, attrLimit) { + return str.length <= attrLimit ? str : str.substring(0, attrLimit) + '...'; +} diff --git a/lib/core/utils/index.js b/lib/core/utils/index.js index 01ce2fa08..44230841d 100644 --- a/lib/core/utils/index.js +++ b/lib/core/utils/index.js @@ -42,6 +42,7 @@ export { default as getStandards } from './get-standards'; export { default as getStyleSheetFactory } from './get-stylesheet-factory'; export { default as getXpath } from './get-xpath'; export { default as getAncestry } from './get-ancestry'; +export { default as getElementSource } from './get-element-source'; export { default as injectStyle } from './inject-style'; export { default as isArrayLike } from './is-array-like'; export { diff --git a/test/core/utils/dq-element.js b/test/core/utils/dq-element.js index dd3fb4063..b360ee09a 100644 --- a/test/core/utils/dq-element.js +++ b/test/core/utils/dq-element.js @@ -46,96 +46,6 @@ describe('DqElement', () => { }); describe('source', () => { - it('should include the outerHTML of the element', () => { - const vNode = queryFixture('
Hello!
'); - const outerHTML = vNode.actualNode.outerHTML; - const result = new DqElement(vNode); - assert.equal(result.source, outerHTML); - }); - - it('should work with SVG elements', () => { - const vNode = queryFixture(''); - const result = new DqElement(vNode); - assert.equal(result.source, vNode.actualNode.outerHTML); - }); - - it('should work with MathML', () => { - const vNode = queryFixture( - '' + - 'x2' + - '' - ); - - const result = new DqElement(vNode); - assert.equal(result.source, vNode.actualNode.outerHTML); - }); - - it('should truncate large elements', () => { - let div = '
'; - for (let i = 0; i < 300; i++) { - div += i; - } - div += '
'; - const vNode = queryFixture(div); - const result = new DqElement(vNode); - assert.equal(result.source, '
'); - }); - - it('should truncate large attributes of large element', () => { - const el = document.createElement('div'); - let attributeName = 'data-'; - let attributeValue = ''; - for (let i = 0; i < 500; i++) { - attributeName += 'foo'; - attributeValue += i; - } - el.setAttribute(attributeName, attributeValue); - - const vNode = new DqElement(el); - assert.equal( - vNode.source, - `
` - ); - }); - - it('should remove attributes for a large element having a large number of attributes', () => { - let customElement = '
`; - const vNode = queryFixture(customElement); - const result = new DqElement(vNode); - const truncatedAttrCount = (result.source.match(/attr/g) || []).length; - assert.isBelow(truncatedAttrCount, 100); - assert.isAtLeast(truncatedAttrCount, 10); - }); - - it('should truncate a large element with long custom tag name', () => { - let longCustomElementTagName = new Array(300).join('b'); - let customElement = `<${longCustomElementTagName} id="target">A`; - const vNode = queryFixture(customElement); - const result = new DqElement(vNode); - assert.equal(result.source, `${customElement.substring(0, 300)} ...>`); - }); - - it('should not truncate attributes if children are long but attribute itself is within limits', () => { - let el = document.createElement('div'); - let attributeValue = ''; - let innerHtml = ''; - for (let i = 0; i < 50; i++) { - attributeValue += 'a'; - innerHtml += 'foobar'; - } - el.setAttribute('long-attribute', attributeValue); - el.innerHTML = innerHtml; - - const vNode = new DqElement(el); - assert.equal(vNode.source, `
`); - }); - it('should use spec object over passed element', () => { const vNode = queryFixture('
Hello!
'); const spec = { source: 'woot' }; diff --git a/test/core/utils/get-element-source.js b/test/core/utils/get-element-source.js new file mode 100644 index 000000000..13b4cd34c --- /dev/null +++ b/test/core/utils/get-element-source.js @@ -0,0 +1,233 @@ +describe('axe.utils.getElementSource', () => { + const getElementSource = axe.utils.getElementSource; + const queryFixture = axe.testUtils.queryFixture; + + afterEach(() => { + axe.reset(); + }); + + it('should be exposed to utils', () => { + assert.equal(typeof axe.utils.getElementSource, 'function'); + }); + + it('should return empty string for null/undefined element', () => { + assert.equal(getElementSource(null), ''); + assert.equal(getElementSource(undefined), ''); + }); + + it('should return nodeValue for text nodes', () => { + const vNode = queryFixture('
Hello world
'); + const textNode = vNode.actualNode.firstChild; + assert.equal(textNode.nodeType, 3); + assert.equal(getElementSource(textNode), 'Hello world'); + }); + + it('should return nodeValue for comment nodes', () => { + const vNode = queryFixture( + '
' + ); + const commentNode = vNode.actualNode.firstChild; + assert.equal(commentNode.nodeType, 8); + assert.equal(getElementSource(commentNode), ' example comment '); + }); + + it('should truncate long nodeValue for non-element nodes', () => { + const textNode = document.createTextNode('x'.repeat(500)); + const result = getElementSource(textNode, { maxLength: 50 }); + assert.equal(result, 'x'.repeat(50) + '...'); + }); + + it('should work without the virtual tree (element not in axe context)', () => { + const el = document.createElement('div'); + el.setAttribute('id', 'standalone'); + el.textContent = 'Hello'; + const result = getElementSource(el); + assert.equal(result, '
Hello
'); + }); + + it('should include the outerHTML of the element', () => { + const vNode = queryFixture('
Hello!
'); + const outerHTML = vNode.actualNode.outerHTML; + const result = getElementSource(vNode.actualNode); + assert.equal(result, outerHTML); + }); + + it('should work with SVG elements', () => { + const vNode = queryFixture(''); + const result = getElementSource(vNode.actualNode); + assert.equal(result, vNode.actualNode.outerHTML); + }); + + it('should work with MathML', () => { + const vNode = queryFixture( + '' + + 'x2' + + '' + ); + + const result = getElementSource(vNode.actualNode); + assert.equal(result, vNode.actualNode.outerHTML); + }); + + describe('XML namespaces', () => { + it('should work with SVG and xlink:href attribute', () => { + const vNode = queryFixture( + '' + + 'Link' + + '' + ); + const result = getElementSource(vNode.actualNode); + + assert.include(result, 'xlink:href'); + assert.include(result, '#section'); + assert.equal(result, vNode.actualNode.outerHTML); + }); + + it('should truncate SVG with namespaced attributes correctly', () => { + const vNode = queryFixture( + '' + + '' + + 'x'.repeat(400) + + '' + + '' + ); + const result = getElementSource(vNode.actualNode, { maxLength: 50 }); + assert.match(result, /$/); + }); + + it('should work with createElementNS for elements in SVG namespace', () => { + const svgNS = 'http://www.w3.org/2000/svg'; + const el = document.createElementNS(svgNS, 'rect'); + el.setAttributeNS(null, 'id', 'target'); + el.setAttribute('width', '100'); + el.setAttribute('height', '50'); + const result = getElementSource(el); + assert.include(result, 'rect'); + assert.include(result, 'id="target"'); + assert.include(result, 'width="100"'); + assert.include(result, 'height="50"'); + assert.equal(result, el.outerHTML); + }); + + it('should work with setAttributeNS for namespaced attributes', () => { + const xlinkNS = 'http://www.w3.org/1999/xlink'; + const svgNS = 'http://www.w3.org/2000/svg'; + const el = document.createElementNS(svgNS, 'image'); + el.setAttributeNS(xlinkNS, 'xlink:href', 'test.png'); + el.setAttributeNS(null, 'id', 'target'); + const result = getElementSource(el); + assert.include(result, 'xlink:href'); + assert.include(result, 'test.png'); + assert.include(result, 'id="target"'); + assert.equal(result, el.outerHTML); + }); + }); + + it('should truncate large elements', () => { + let div = '
'; + for (let i = 0; i < 300; i++) { + div += i; + } + div += '
'; + const vNode = queryFixture(div); + const result = getElementSource(vNode.actualNode); + assert.equal(result, '
'); + }); + + it('should truncate large attributes of large element', () => { + const el = document.createElement('div'); + let attributeName = 'data-'; + let attributeValue = ''; + for (let i = 0; i < 500; i++) { + attributeName += 'foo'; + attributeValue += i; + } + el.setAttribute(attributeName, attributeValue); + + const result = getElementSource(el); + assert.equal( + result, + `
` + ); + }); + + it('should remove attributes for a large element having a large number of attributes', () => { + let customElement = '
`; + + const vNode = queryFixture(customElement); + const result = getElementSource(vNode.actualNode); + const truncatedAttrCount = (result.match(/attr/g) || []).length; + assert.isBelow(truncatedAttrCount, 100); + assert.isAtLeast(truncatedAttrCount, 10); + }); + + it('should truncate a large element with long custom tag name', () => { + let longCustomElementTagName = new Array(300).join('b'); + let customElement = `<${longCustomElementTagName} id="target">A`; + const vNode = queryFixture(customElement); + const result = getElementSource(vNode.actualNode); + assert.equal(result, `${customElement.substring(0, 300)} ...>`); + }); + + it('should not truncate attributes if children are long but attribute itself is within limits', () => { + let el = document.createElement('div'); + let attributeValue = ''; + let innerHtml = ''; + for (let i = 0; i < 50; i++) { + attributeValue += 'a'; + innerHtml += 'foobar'; + } + el.setAttribute('long-attribute', attributeValue); + el.innerHTML = innerHtml; + + const result = getElementSource(el); + assert.equal(result, `
`); + }); + + describe('options', () => { + it('should respect custom maxLength', () => { + const vNode = queryFixture( + '
' + 'x'.repeat(200) + '
' + ); + const result = getElementSource(vNode.actualNode, { maxLength: 25 }); + assert.equal(result, '
'); + }); + + it('should respect custom attrLimit', () => { + const el = document.createElement('div'); + const longName = 'data-' + 'x'.repeat(300); + const longValue = 'y'.repeat(300); + el.setAttribute(longName, longValue); + + const result = getElementSource(el, { attrLimit: 10 }); + assert.equal(result, '
'); + }); + + it('should include later attributes that fit after skipping long ones', () => { + const vNode = queryFixture( + '
content
' + ); + const result = getElementSource(vNode.actualNode, { maxLength: 50 }); + assert.equal(result, '
'); + }); + + it('should use defaults when options is empty', () => { + let div = '
'; + for (let i = 0; i < 300; i++) { + div += i; + } + div += '
'; + const vNode = queryFixture(div); + const result = getElementSource(vNode.actualNode, {}); + assert.equal(result, '
'); + }); + }); +}); From 99d1e77f351db586c79020372efc59608e604a1c Mon Sep 17 00:00:00 2001 From: KAMIHARA Takumi <65489256+camiha@users.noreply.github.com> Date: Wed, 18 Feb 2026 21:29:20 +0900 Subject: [PATCH 12/32] fix(aria): prevent getOwnedVirtual from returning duplicate nodes (#4987) When a child element is also referenced via aria-owns, getOwnedVirtual returned the same node twice. Filter aria-owns references that already exist in children using Set. Closes: #4840 --------- Co-authored-by: Wilco Fiers --- lib/commons/aria/get-owned-virtual.js | 10 ++++- test/commons/aria/get-owned-virtual.js | 56 ++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/lib/commons/aria/get-owned-virtual.js b/lib/commons/aria/get-owned-virtual.js index 5b24b7bdb..c65bc9ae9 100644 --- a/lib/commons/aria/get-owned-virtual.js +++ b/lib/commons/aria/get-owned-virtual.js @@ -18,7 +18,15 @@ function getOwnedVirtual(virtualNode) { const owns = idrefs(actualNode, 'aria-owns') .filter(element => !!element) .map(element => axe.utils.getNodeFromTree(element)); - return [...children, ...owns]; + + // Deduplicates by first occurrence to match browser accessibility tree behavior + // See: https://github.com/dequelabs/axe-core/pull/4987 + const uniqueOwns = owns.filter((own, index) => owns.indexOf(own) === index); + const nativeChildren = children.filter( + child => !uniqueOwns.includes(child) + ); + + return [...nativeChildren, ...uniqueOwns]; } return [...children]; diff --git a/test/commons/aria/get-owned-virtual.js b/test/commons/aria/get-owned-virtual.js index 6011c16af..a01277ca1 100644 --- a/test/commons/aria/get-owned-virtual.js +++ b/test/commons/aria/get-owned-virtual.js @@ -37,6 +37,62 @@ describe('aria.getOwnedVirtual', function () { assert.equal(owned[3].actualNode.nodeName.toUpperCase(), 'H4'); }); + it('does not return duplicate when child is also aria-owned', function () { + fixtureSetup( + '
' + + '' + + '
' + ); + var target = axe.utils.querySelectorAll(axe._tree[0], '#target')[0]; + var owned = aria.getOwnedVirtual(target); + assert.lengthOf(owned, 1); + assert.equal(owned[0].actualNode.id, 'foo'); + }); + + it('does not return duplicate when same ID appears multiple times in aria-owns', function () { + fixtureSetup( + '
' + + '
' + + '
A
' + + '
B
' + ); + var target = axe.utils.querySelectorAll(axe._tree[0], '#target')[0]; + var owned = aria.getOwnedVirtual(target); + assert.lengthOf(owned, 2); + assert.equal(owned[0].actualNode.id, 'a'); + assert.equal(owned[1].actualNode.id, 'b'); + }); + + it('moves aria-owned child to the end', function () { + fixtureSetup( + '
' + + '
A
' + + '
B
' + + '
' + ); + var target = axe.utils.querySelectorAll(axe._tree[0], '#target')[0]; + var owned = aria.getOwnedVirtual(target); + assert.lengthOf(owned, 2); + assert.equal(owned[0].actualNode.id, 'b'); + assert.equal(owned[1].actualNode.id, 'a'); + }); + + it('moves multiple aria-owned children to the end in aria-owns order', function () { + fixtureSetup( + '
' + + '
A
' + + '
B
' + + '
C
' + + '
' + ); + var target = axe.utils.querySelectorAll(axe._tree[0], '#target')[0]; + var owned = aria.getOwnedVirtual(target); + assert.lengthOf(owned, 3); + assert.equal(owned[0].actualNode.id, 'b'); + assert.equal(owned[1].actualNode.id, 'c'); + assert.equal(owned[2].actualNode.id, 'a'); + }); + it('ignores whitespace-only aria-owned', function () { fixtureSetup( '
' + From 69d81c1cbb6a61a272884516c7983dcd17d28a42 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Fri, 20 Feb 2026 10:15:10 -0700 Subject: [PATCH 13/32] fix(target-size): determine offset using clientRects if target is display:inline (#5012) This pr does two things: 1. For target size we decided to calculate the visible unobscured rects by taking the bounding rect of the target and subtracting the client rects of the obscurer if the obscurer is inline. This is because an inline element only accepts pointer events on the client rects and not the bounding rect. For the target we still take the bounding rect and not the client rects if the target is inline because we both agreed that the goal of the target size rule is to prevent clicking on the wrong target and not that the target itself is large enough to click on. So an inline element with multiple lines would have dead pointer zones within it, but accidentally clicking on a dead zone is not a failure of target size. 2. This also applies using client rects for inline elements for the spacing exception for the same reasons as above. What this does is allow checking multiple target rects for inline nodes and makes sure each rect passes the spacing exception. If at least one rect does not pass the rule fails for that element. Closes: https://github.com/dequelabs/axe-core/issues/4928 --- lib/checks/mobile/target-size-evaluate.js | 21 ++++++--- lib/commons/dom/get-target-rects.js | 20 ++++++--- lib/commons/math/get-offset.js | 44 +++++++++---------- lib/commons/math/split-rects.js | 4 +- test/checks/mobile/target-offset.js | 39 ++++++++++++++++ test/checks/mobile/target-size.js | 30 +++++++++++++ test/commons/dom/get-target-rects.js | 10 +++++ test/commons/math/split-rects.js | 16 +++++++ .../rules/target-size/target-size.html | 21 +++++++++ .../rules/target-size/target-size.json | 7 +++ 10 files changed, 176 insertions(+), 36 deletions(-) diff --git a/lib/checks/mobile/target-size-evaluate.js b/lib/checks/mobile/target-size-evaluate.js index 1fb76e775..a87935d54 100644 --- a/lib/checks/mobile/target-size-evaluate.js +++ b/lib/checks/mobile/target-size-evaluate.js @@ -66,7 +66,11 @@ export default function targetSizeEvaluate(node, options, vNode) { return true; } - const largestInnerRect = getLargestUnobscuredArea(vNode, obscuredWidgets); + const largestInnerRect = getLargestUnobscuredArea( + vNode, + obscuredWidgets, + minSize + ); if (!largestInnerRect) { this.data({ minSize, messageKey: 'tooManyRects' }); return undefined; @@ -127,11 +131,16 @@ function filterByElmsOverlap(vNode, nearbyElms) { } // Find areas of the target that are not obscured -function getLargestUnobscuredArea(vNode, obscuredNodes) { +function getLargestUnobscuredArea(vNode, obscuredNodes, minSize) { const nodeRect = vNode.boundingClientRect; - const obscuringRects = obscuredNodes.map( - ({ boundingClientRect: rect }) => rect - ); + const obscuringRects = obscuredNodes + .map(obscuredNode => { + const display = obscuredNode.getComputedStylePropertyValue('display'); + return display === 'inline' + ? obscuredNode.clientRects + : obscuredNode.boundingClientRect; + }) + .flat(Infinity); let unobscuredRects; try { unobscuredRects = splitRects(nodeRect, obscuringRects); @@ -140,7 +149,7 @@ function getLargestUnobscuredArea(vNode, obscuredNodes) { } // Of the unobscured inner rects, work out the largest - return getLargestRect(unobscuredRects); + return getLargestRect(unobscuredRects, minSize); } // Find the largest rectangle in the array, prioritize ones that meet a minimum size diff --git a/lib/commons/dom/get-target-rects.js b/lib/commons/dom/get-target-rects.js index a2bc2eec1..ebebb2c7f 100644 --- a/lib/commons/dom/get-target-rects.js +++ b/lib/commons/dom/get-target-rects.js @@ -13,7 +13,9 @@ export default memoize(getTargetRects); * @return {DOMRect[]} */ function getTargetRects(vNode) { - const nodeRect = vNode.boundingClientRect; + const display = vNode.getComputedStylePropertyValue('display'); + const nodeRects = + display === 'inline' ? vNode.clientRects : [vNode.boundingClientRect]; const overlappingVNodes = findNearbyElms(vNode).filter(vNeighbor => { return ( hasVisualOverlap(vNode, vNeighbor) && @@ -23,13 +25,19 @@ function getTargetRects(vNode) { }); if (!overlappingVNodes.length) { - return [nodeRect]; + return nodeRects; } - const obscuringRects = overlappingVNodes.map( - ({ boundingClientRect: rect }) => rect - ); - return splitRects(nodeRect, obscuringRects); + const obscuringRects = overlappingVNodes + .map(overlappingVNode => { + const overlappingDisplay = + overlappingVNode.getComputedStylePropertyValue('display'); + return overlappingDisplay === 'inline' + ? overlappingVNode.clientRects + : overlappingVNode.boundingClientRect; + }) + .flat(Infinity); + return splitRects(nodeRects, obscuringRects); } function isDescendantNotInTabOrder(vAncestor, vNode) { diff --git a/lib/commons/math/get-offset.js b/lib/commons/math/get-offset.js index 957d4e43c..40f0e9529 100644 --- a/lib/commons/math/get-offset.js +++ b/lib/commons/math/get-offset.js @@ -21,33 +21,33 @@ export default function getOffset(vTarget, vNeighbor, minRadiusNeighbour = 12) { return null; } - const targetBoundingBox = targetRects.reduce(getBoundingRect); - const targetCenter = getRectCenter(targetBoundingBox); + // calculate distance of each target rect to the closest edge of each neighbor rect + return targetRects.reduce((minDistance, targetRect) => { + const targetCenter = getRectCenter(targetRect); - // calculate distance to the closest edge of each neighbor rect - let minDistance = Infinity; - for (const rect of neighborRects) { - if (isPointInRect(targetCenter, rect)) { - return 0; - } + for (const rect of neighborRects) { + if (isPointInRect(targetCenter, rect)) { + return 0; + } - const closestPoint = getClosestPoint(targetCenter, rect); - const distance = pointDistance(targetCenter, closestPoint); - minDistance = Math.min(minDistance, distance); - } + const closestPoint = getClosestPoint(targetCenter, rect); + const distance = pointDistance(targetCenter, closestPoint); + minDistance = Math.min(minDistance, distance); + } - const neighborTargetSize = getTargetSize(vNeighbor); - if (rectHasMinimumSize(minRadiusNeighbour * 2, neighborTargetSize)) { - return minDistance; - } + const neighborTargetSize = getTargetSize(vNeighbor); + if (rectHasMinimumSize(minRadiusNeighbour * 2, neighborTargetSize)) { + return minDistance; + } - const neighborBoundingBox = neighborRects.reduce(getBoundingRect); - const neighborCenter = getRectCenter(neighborBoundingBox); - // subtract the radius of the circle from the distance to center to get distance to edge of the neighbor circle - const centerDistance = - pointDistance(targetCenter, neighborCenter) - minRadiusNeighbour; + const neighborBoundingBox = neighborRects.reduce(getBoundingRect); + const neighborCenter = getRectCenter(neighborBoundingBox); + // subtract the radius of the circle from the distance to center to get distance to edge of the neighbor circle + const centerDistance = + pointDistance(targetCenter, neighborCenter) - minRadiusNeighbour; - return Math.max(0, Math.min(minDistance, centerDistance)); + return Math.max(0, Math.min(minDistance, centerDistance)); + }, Infinity); } function getClosestPoint(point, rect) { diff --git a/lib/commons/math/split-rects.js b/lib/commons/math/split-rects.js index ea6ba5397..aeb651e57 100644 --- a/lib/commons/math/split-rects.js +++ b/lib/commons/math/split-rects.js @@ -3,12 +3,12 @@ * space that does not overlap. * @method getOffset * @memberof axe.commons.math - * @param {DOMRect} outerRect + * @param {DOMRect|DOMRect[]} outerRect * @param {DOMRect[]} overlapRects * @returns {DOMRect[]} Unique array of rects */ export default function splitRects(outerRect, overlapRects) { - let uniqueRects = [outerRect]; + let uniqueRects = Array.isArray(outerRect) ? outerRect : [outerRect]; for (const overlapRect of overlapRects) { uniqueRects = uniqueRects.reduce((rects, inputRect) => { return rects.concat(splitRect(inputRect, overlapRect)); diff --git a/test/checks/mobile/target-offset.js b/test/checks/mobile/target-offset.js index 747d9a4fa..942690f3c 100644 --- a/test/checks/mobile/target-offset.js +++ b/test/checks/mobile/target-offset.js @@ -34,6 +34,19 @@ describe('target-offset tests', () => { assert.closeTo(checkContext._data.closestOffset, 24, 0.2); }); + it('returns true when wrapped inline elements offset is 24px', () => { + const checkArgs = checkSetup(` + + `); + + assert.isTrue(checkEvaluate.apply(checkContext, checkArgs)); + assert.equal(checkContext._data.minOffset, 24); + assert.closeTo(checkContext._data.closestOffset, 24, 0.2); + }); + describe('when the offset is insufficient', () => { it('returns false for targets in the tab order', () => { const checkArgs = checkSetup( @@ -66,6 +79,32 @@ describe('target-offset tests', () => { assert.equal(checkContext._data.minOffset, 24); assert.closeTo(checkContext._data.closestOffset, 22, 0.2); }); + + it('returns false when wrapped inline elements offset is <24px', () => { + const checkArgs = checkSetup(` + + `); + + assert.isFalse(checkEvaluate.apply(checkContext, checkArgs)); + assert.equal(checkContext._data.minOffset, 24); + assert.closeTo(checkContext._data.closestOffset, 20, 3); + }); + + it('returns false when one line of a wrapped inline elements offset is <24px', () => { + const checkArgs = checkSetup(` + + `); + + assert.isFalse(checkEvaluate.apply(checkContext, checkArgs)); + assert.equal(checkContext._data.minOffset, 24); + assert.closeTo(checkContext._data.closestOffset, 15.5, 5); + }); }); it('ignores non-widget elements as neighbors', () => { diff --git a/test/checks/mobile/target-size.js b/test/checks/mobile/target-size.js index f0769c3c5..bebd01703 100644 --- a/test/checks/mobile/target-size.js +++ b/test/checks/mobile/target-size.js @@ -176,6 +176,36 @@ describe('target-size tests', () => { assert.deepEqual(elmIds(checkContext._relatedNodes), ['#obscurer']); }); + it('returns true for obscured target when an unobscured rect has sufficient size but smaller area', () => { + const checkArgs = checkSetup(` +
+ + +
+ `); + assert.isTrue(check.evaluate.apply(checkContext, checkArgs)); + assert.deepEqual(checkContext._data, { + minSize: 24, + width: 30, + height: 40 + }); + assert.deepEqual(elmIds(checkContext._relatedNodes), ['#obscurer']); + }); + + it('returns true for multiline inline target with sufficient space', () => { + const checkArgs = checkSetup(` + + `); + assert.isTrue(check.evaluate.apply(checkContext, checkArgs)); + assert.closeTo(checkContext._data.width, 40.5, 10); + assert.closeTo(checkContext._data.height, 40.5, 5); + assert.deepEqual(elmIds(checkContext._relatedNodes), ['#obscurer']); + }); + it('returns undefined if there are too many focusable widgets', () => { let html = ''; for (let i = 0; i < 100; i++) { diff --git a/test/commons/dom/get-target-rects.js b/test/commons/dom/get-target-rects.js index be37b7cbb..6f3a7373a 100644 --- a/test/commons/dom/get-target-rects.js +++ b/test/commons/dom/get-target-rects.js @@ -96,4 +96,14 @@ describe('get-target-rects', () => { const rects = getTargetRects(vNode); assert.deepEqual(rects, [vNode.actualNode.getBoundingClientRect()]); }); + + it('uses client rects if target is inline', () => { + const vNode = queryFixture(` + + `); + const rects = getTargetRects(vNode); + assert.deepEqual(rects, Array.from(vNode.actualNode.getClientRects())); + }); }); diff --git a/test/commons/math/split-rects.js b/test/commons/math/split-rects.js index 968b8c7b7..c0579d095 100644 --- a/test/commons/math/split-rects.js +++ b/test/commons/math/split-rects.js @@ -28,6 +28,14 @@ describe('splitRects', () => { }, 'splitRects: Too many rects'); }); + it('accepts an array of rects', () => { + const rectA = new DOMRect(0, 0, 100, 50); + const rectB = new DOMRect(0, 50, 50, 50); + const rects = splitRects([rectA], [rectB]); + assert.lengthOf(rects, 1); + assert.deepEqual(rects[0], rectA); + }); + describe('with one overlapping rect', () => { it('returns one rect if overlaps covers two corners', () => { const rectA = new DOMRect(0, 0, 100, 50); @@ -73,6 +81,14 @@ describe('splitRects', () => { const rects = splitRects(rectA, [rectB]); assert.lengthOf(rects, 0); }); + + it('accepts an array of rects', () => { + const rectA = new DOMRect(0, 0, 100, 50); + const rectB = new DOMRect(40, 0, 100, 50); + const rects = splitRects([rectA], [rectB]); + assert.lengthOf(rects, 1); + assert.deepEqual(rects[0], new DOMRect(0, 0, 40, 50)); + }); }); describe('with multiple overlaps', () => { diff --git a/test/integration/rules/target-size/target-size.html b/test/integration/rules/target-size/target-size.html index 7a2d02180..c57bd9e7b 100644 --- a/test/integration/rules/target-size/target-size.html +++ b/test/integration/rules/target-size/target-size.html @@ -145,6 +145,27 @@ >

+ + + + +
+ + +
+

Date: Wed, 4 Mar 2026 09:10:18 -0500 Subject: [PATCH 14/32] fix(existing-rule): aria-busy now shows an error message for a use with unallowed children (#5017) Updated existing rule for aria-required-children for cases where the aria-busy attribute is used. This now will show the user a specific error message regarding aria-busy with unallowed children instead of the one for used for other cases using unallowed children. Replaces PR: [5011](https://github.com/dequelabs/axe-core/pull/5011) Closes: https://github.com/dequelabs/axe-core/issues/4626 --- lib/checks/aria/aria-required-children-evaluate.js | 5 ++++- lib/checks/aria/aria-required-children.json | 3 ++- locales/_template.json | 3 ++- test/checks/aria/required-children.js | 4 ++-- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/checks/aria/aria-required-children-evaluate.js b/lib/checks/aria/aria-required-children-evaluate.js index 1e7512d96..403cd4979 100644 --- a/lib/checks/aria/aria-required-children-evaluate.js +++ b/lib/checks/aria/aria-required-children-evaluate.js @@ -41,8 +41,11 @@ export default function ariaRequiredChildrenEvaluate( if (unallowed.length) { this.relatedNodes(unallowed.map(({ vNode }) => vNode)); + const messageKey = + virtualNode.attr('aria-busy') === 'true' ? 'aria-busy-fail' : 'unallowed'; + this.data({ - messageKey: 'unallowed', + messageKey, values: unallowed .map(({ vNode, attr }) => getUnallowedSelector(vNode, attr)) .filter((selector, index, array) => array.indexOf(selector) === index) diff --git a/lib/checks/aria/aria-required-children.json b/lib/checks/aria/aria-required-children.json index 16c67dbd5..016f56b5e 100644 --- a/lib/checks/aria/aria-required-children.json +++ b/lib/checks/aria/aria-required-children.json @@ -27,7 +27,8 @@ "fail": { "singular": "Required ARIA child role not present: ${data.values}", "plural": "Required ARIA children role not present: ${data.values}", - "unallowed": "Element has children which are not allowed: ${data.values}" + "unallowed": "Element has children which are not allowed: ${data.values}", + "aria-busy-fail": "Element has children which are not allowed: ${data.values}; Having aria-busy=\"true\" does not allow children with roles that are not allowed" }, "incomplete": { "singular": "Expecting ARIA child role to be added: ${data.values}", diff --git a/locales/_template.json b/locales/_template.json index 70203bd75..771d26ef3 100644 --- a/locales/_template.json +++ b/locales/_template.json @@ -509,7 +509,8 @@ "fail": { "singular": "Required ARIA child role not present: ${data.values}", "plural": "Required ARIA children role not present: ${data.values}", - "unallowed": "Element has children which are not allowed: ${data.values}" + "unallowed": "Element has children which are not allowed: ${data.values}", + "aria-busy-fail": "Element has children which are not allowed: ${data.values}; Having aria-busy=\"true\" does not allow children with roles that are not allowed" }, "incomplete": { "singular": "Expecting ARIA child role to be added: ${data.values}", diff --git a/test/checks/aria/required-children.js b/test/checks/aria/required-children.js index faf68eb71..8cfab3a17 100644 --- a/test/checks/aria/required-children.js +++ b/test/checks/aria/required-children.js @@ -146,14 +146,14 @@ describe('aria-required-children', () => { }); }); - it('should fail list with an unallowed child, even if aria-busy="true"', () => { + it('should fail list with an unallowed child but show a custom message, even if aria-busy="true"', () => { const params = checkSetup(`

`); assert.isFalse(requiredChildrenCheck.apply(checkContext, params)); assert.deepEqual(checkContext._data, { - messageKey: 'unallowed', + messageKey: 'aria-busy-fail', values: '[role=tabpanel]' }); }); From 68aab66a740910a90caa480d63261529c2a84af9 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Sat, 7 Mar 2026 04:50:57 -0700 Subject: [PATCH 15/32] test: fix chromedriver 146 failing to create session (#5026) Similar to our fix in [axe-core-npm](https://github.com/dequelabs/axe-core-npm/pull/1291) this pins chrome/driver to v145 in order to fix the failing tests due to chromedriver crashing or failing to create a session. It also fixes the memory issue in https://github.com/dequelabs/axe-core/issues/5018 and adds some chrome options that are good for ci usage. I also created a tech debt ticket to track the pin. See https://github.com/dequelabs/axe-core/actions/runs/22737133182?pr=5026 that it shows 10 successful runs. Closes: #501 --- .github/actions/install-deps/action.yml | 3 ++- test/act-rules/act-runner.js | 2 +- test/aria-practices/apg.spec.js | 2 +- test/get-webdriver.js | 7 ++++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/actions/install-deps/action.yml b/.github/actions/install-deps/action.yml index b7d220b7f..40c9aa43d 100644 --- a/.github/actions/install-deps/action.yml +++ b/.github/actions/install-deps/action.yml @@ -56,7 +56,8 @@ runs: id: setup-chrome uses: browser-actions/setup-chrome@b94431e051d1c52dcbe9a7092a4f10f827795416 # v2.1.0 with: - chrome-version: ${{ inputs.nightly == 'true' && 'beta' || 'stable' }} + # @see https://github.com/dequelabs/axe-core/issues/5027 + chrome-version: ${{ inputs.nightly == 'true' && 'beta' || 145 }} install-chromedriver: true install-dependencies: true - name: Install Firefox diff --git a/test/act-rules/act-runner.js b/test/act-rules/act-runner.js index 3d3eab094..ae3a10fd6 100644 --- a/test/act-rules/act-runner.js +++ b/test/act-rules/act-runner.js @@ -47,7 +47,7 @@ module.exports = ({ id, title, axeRules, skipTests = [] }) => { }); after(async () => { - await driver.close(); + await driver.quit(); await new Promise(r => server.close(r)); }); diff --git a/test/aria-practices/apg.spec.js b/test/aria-practices/apg.spec.js index e03a4cc06..aaebe6f14 100644 --- a/test/aria-practices/apg.spec.js +++ b/test/aria-practices/apg.spec.js @@ -28,7 +28,7 @@ describe('aria-practices', function () { }); after(async () => { - await driver.close(); + await driver.quit(); }); const disabledRules = { diff --git a/test/get-webdriver.js b/test/get-webdriver.js index c71a55710..ce38fdaa4 100644 --- a/test/get-webdriver.js +++ b/test/get-webdriver.js @@ -5,7 +5,12 @@ const chromedriverPath = const getWebdriver = () => { const service = new chrome.ServiceBuilder(chromedriverPath); - const options = new chrome.Options().addArguments('--headless'); + const options = new chrome.Options().addArguments( + '--headless', + '--no-sandbox', + '--disable-dev-shm-usage', + '--disable-gpu' + ); if (process.env.CHROME_BIN) { options.setBinaryPath(process.env.CHROME_BIN); From 431f621b28b7db3477ba660f38b36b56940c43a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 20:39:39 -0400 Subject: [PATCH 16/32] chore: bump jsdom from 27.4.0 to 28.1.0 (#5021) Bumps [jsdom](https://github.com/jsdom/jsdom) from 27.4.0 to 28.1.0.
Release notes

Sourced from jsdom's releases.

Version 28.1.0

  • Added blob.text(), blob.arrayBuffer(), and blob.bytes() methods.
  • Improved getComputedStyle() to account for CSS specificity when multiple rules apply. (asamuzaK)
  • Improved synchronous XMLHttpRequest performance by using a persistent worker thread, avoiding ~400ms of setup overhead on every synchronous request after the first one.
  • Improved performance of node.getRootNode(), node.isConnected, and event.dispatchEvent() by caching the root node of document-connected trees.
  • Fixed getComputedStyle() to correctly handle !important priority. (asamuzaK)
  • Fixed document.getElementById() to return the first element in tree order when multiple elements share the same ID.
  • Fixed <svg> elements to no longer incorrectly proxy event handlers to the Window.
  • Fixed FileReader event timing and fileReader.result state to more closely follow the spec.
  • Fixed a potential hang when synchronous XMLHttpRequest encountered dispatch errors.
  • Fixed compatibility with environments where Node.js's built-in fetch() has been used before importing jsdom, by working around undici v6/v7 incompatibilities.

Version 28.0.0

  • Overhauled resource loading customization. See the new README for details on the new API.
  • Added MIME type sniffing to <iframe> and <frame> loads.
  • Regression: WebSockets are no longer correctly throttled to one connection per origin. This is a result of the bug at nodejs/undici#4743.
  • Fixed decoding of the query components of <a> and <area> elements in non-UTF-8 documents.
  • Fixed XMLHttpRequest fetches and WebSocket upgrade requests to be interceptable by the new customizable resource loading. (Except synchronous XMLHttpRequests.)
  • Fixed the referrer of a document to be set correctly when redirects are involved; it is now the initiating page, not the last hop in the redirect chain.
  • Fixed correctness bugs when passing ArrayBuffers or typed arrays to various APIs, where they would not correctly snapshot the data.
  • Fixed require("url").parse() deprecation warning when using WebSockets.
  • Fixed <iframe>, <frame>, and <img> (when canvas is installed) to fire load events, not error events, on non-OK HTTP responses.
  • Fixed many small issues in XMLHttpRequest.
Changelog

Sourced from jsdom's changelog.

28.1.0

  • Added blob.text(), blob.arrayBuffer(), and blob.bytes() methods.
  • Improved getComputedStyle() to account for CSS specificity when multiple rules apply. (asamuzaK)
  • Improved synchronous XMLHttpRequest performance by using a persistent worker thread, avoiding ~400ms of setup overhead on every synchronous request after the first one.
  • Improved performance of node.getRootNode(), node.isConnected, and event.dispatchEvent() by caching the root node of document-connected trees.
  • Fixed getComputedStyle() to correctly handle !important priority. (asamuzaK)
  • Fixed document.getElementById() to return the first element in tree order when multiple elements share the same ID.
  • Fixed <svg> elements to no longer incorrectly proxy event handlers to the Window.
  • Fixed FileReader event timing and fileReader.result state to more closely follow the spec.
  • Fixed a potential hang when synchronous XMLHttpRequest encountered dispatch errors.
  • Fixed compatibility with environments where Node.js's built-in fetch() has been used before importing jsdom, by working around undici v6/v7 incompatibilities.

28.0.0

  • Overhauled resource loading customization. See the new README for details on the new API.
  • Added MIME type sniffing to <iframe> and <frame> loads.
  • Regression: WebSockets are no longer correctly throttled to one connection per origin. This is a result of the bug at nodejs/undici#4743.
  • Fixed decoding of the query components of <a> and <area> elements in non-UTF-8 documents.
  • Fixed XMLHttpRequest fetches and WebSocket upgrade requests to be interceptable by the new customizable resource loading. (Except synchronous XMLHttpRequests.)
  • Fixed the referrer of a document to be set correctly when redirects are involved; it is now the initiating page, not the last hop in the redirect chain.
  • Fixed correctness bugs when passing ArrayBuffers or typed arrays to various APIs, where they would not correctly snapshot the data.
  • Fixed require("url").parse() deprecation warning when using WebSockets.
  • Fixed <iframe>, <frame>, and <img> (when canvas is installed) to fire load events, not error events, on non-OK HTTP responses.
  • Fixed many small issues in XMLHttpRequest.
Commits
  • 12949b5 Version 28.1.0
  • ce4c58f Apply CSS specificity when computing styles
  • 7ed55a0 Skip single-byte-decoder encoding tests on Node 20
  • f3b1973 Generalize node version conditions in test expectations
  • 853c596 Rewrite getElementById ID caching for tree-order correctness
  • 5fbfde6 Fix potential sync XHR worker hang from unhandled dispatch errors
  • 82df38f Cache the root node for document-connected trees
  • ed7c5c0 Add documentation comment to create-event-accessor.js
  • b4562e9 Simplify Window.js installEventHandlers
  • 7da340f Centralize "determine the target of an event handler"
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=jsdom&package-manager=npm_and_yarn&previous-version=27.4.0&new-version=28.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) 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-automerge-start) [//]: # (dependabot-automerge-end) ---
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 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)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 384 +++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 213 insertions(+), 173 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6e7580ca7..593201387 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,7 @@ "inquirer": "^8.2.5", "jquery": "^4.0.0", "jsdoc": "^4.0.2", - "jsdom": "^27.0.0", + "jsdom": "^28.1.0", "karma": "^6.4.1", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^3.1.1", @@ -93,50 +93,53 @@ } }, "node_modules/@acemir/cssom": { - "version": "0.9.30", - "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.30.tgz", - "integrity": "sha512-9CnlMCI0LmCIq0olalQqdWrJHPzm0/tw3gzOA9zJSgvFX7Xau3D24mAGa4BtwxwY69nsuJW6kQqqCzf/mEcQgg==", + "version": "0.9.31", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", + "integrity": "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==", "dev": true }, "node_modules/@asamuzakjp/css-color": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.1.tgz", - "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.0.1.tgz", + "integrity": "sha512-2SZFvqMyvboVV1d15lMf7XiI3m7SDqXUuKaTymJYLN6dSGadqp+fVojqJlVoMlbZnlTmu3S0TLwLTJpvBMO1Aw==", "dev": true, "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "lru-cache": "^11.2.4" + "@csstools/css-calc": "^3.1.1", + "@csstools/css-color-parser": "^4.0.2", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.2.6" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "dev": true, "engines": { "node": "20 || >=22" } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "6.7.6", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.6.tgz", - "integrity": "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", "dev": true, "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.4" + "lru-cache": "^11.2.6" } }, "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "dev": true, "engines": { "node": "20 || >=22" @@ -1701,6 +1704,18 @@ "integrity": "sha512-RzahvqTkfpY2jsDxo8YItPX+/iZ6hbiikw1YhE0bA9EKBR5Og8Pa6FHn9PO9M0zaXRVsr0GFQLKbB/0rzy9SzA==", "dev": true }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -1711,9 +1726,9 @@ } }, "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", "dev": true, "funding": [ { @@ -1726,13 +1741,13 @@ } ], "engines": { - "node": ">=18" + "node": ">=20.19.0" } }, "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.1.1.tgz", + "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", "dev": true, "funding": [ { @@ -1745,17 +1760,17 @@ } ], "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.0.2.tgz", + "integrity": "sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==", "dev": true, "funding": [ { @@ -1768,21 +1783,21 @@ } ], "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.1.1" }, "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", "dev": true, "funding": [ { @@ -1795,16 +1810,16 @@ } ], "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.22.tgz", - "integrity": "sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw==", + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.28.tgz", + "integrity": "sha512-1NRf1CUBjnr3K7hu8BLxjQrKCxEe8FP/xmPTenAxCRZWVLbmGotkFvG9mfNpjA6k7Bw1bw4BilZq9cu19RA5pg==", "dev": true, "funding": [ { @@ -1815,15 +1830,12 @@ "type": "opencollective", "url": "https://opencollective.com/csstools" } - ], - "engines": { - "node": ">=18" - } + ] }, "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", "dev": true, "funding": [ { @@ -1836,7 +1848,7 @@ } ], "engines": { - "node": ">=18" + "node": ">=20.19.0" } }, "node_modules/@deque/dot": { @@ -4347,24 +4359,24 @@ } }, "node_modules/cssstyle": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.6.tgz", - "integrity": "sha512-legscpSpgSAeGEe0TNcai97DKt9Vd9AsAdOL7Uoetb52Ar/8eJm3LIa39qpv8wWzLFlNG4vVvppQM+teaMPj3A==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.1.0.tgz", + "integrity": "sha512-Ml4fP2UT2K3CUBQnVlbdV/8aFDdlY69E+YnwJM+3VUWl08S3J8c8aRuJqCkD9Py8DHZ7zNNvsfKl8psocHZEFg==", "dev": true, "dependencies": { - "@asamuzakjp/css-color": "^4.1.1", - "@csstools/css-syntax-patches-for-csstree": "^1.0.21", + "@asamuzakjp/css-color": "^5.0.0", + "@csstools/css-syntax-patches-for-csstree": "^1.0.28", "css-tree": "^3.1.0", - "lru-cache": "^11.2.4" + "lru-cache": "^11.2.6" }, "engines": { "node": ">=20" } }, "node_modules/cssstyle/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "dev": true, "engines": { "node": "20 || >=22" @@ -4399,16 +4411,16 @@ } }, "node_modules/data-urls": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", - "integrity": "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", "dev": true, "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.0.0" + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" }, "engines": { - "node": ">=20" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/date-format": { @@ -7974,16 +7986,17 @@ } }, "node_modules/jsdom": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.4.0.tgz", - "integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.1.0.tgz", + "integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==", "dev": true, "dependencies": { - "@acemir/cssom": "^0.9.28", - "@asamuzakjp/dom-selector": "^6.7.6", - "@exodus/bytes": "^1.6.0", - "cssstyle": "^5.3.4", - "data-urls": "^6.0.0", + "@acemir/cssom": "^0.9.31", + "@asamuzakjp/dom-selector": "^6.8.1", + "@bramus/specificity": "^2.4.2", + "@exodus/bytes": "^1.11.0", + "cssstyle": "^6.0.1", + "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", "http-proxy-agent": "^7.0.2", @@ -7993,11 +8006,11 @@ "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.0", + "undici": "^7.21.0", "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^8.0.0", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.1.0", - "ws": "^8.18.3", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0", "xml-name-validator": "^5.0.0" }, "engines": { @@ -12619,6 +12632,15 @@ "node": "*" } }, + "node_modules/undici": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", + "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", + "dev": true, + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", @@ -12876,9 +12898,9 @@ } }, "node_modules/webidl-conversions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.0.tgz", - "integrity": "sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", "dev": true, "engines": { "node": ">=20" @@ -12932,25 +12954,26 @@ } }, "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", "dev": true, "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/whatwg-url": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz", - "integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", "dev": true, "dependencies": { + "@exodus/bytes": "^1.11.0", "tr46": "^6.0.0", - "webidl-conversions": "^8.0.0" + "webidl-conversions": "^8.0.1" }, "engines": { - "node": ">=20" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/which": { @@ -13308,49 +13331,49 @@ "dev": true }, "@acemir/cssom": { - "version": "0.9.30", - "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.30.tgz", - "integrity": "sha512-9CnlMCI0LmCIq0olalQqdWrJHPzm0/tw3gzOA9zJSgvFX7Xau3D24mAGa4BtwxwY69nsuJW6kQqqCzf/mEcQgg==", + "version": "0.9.31", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", + "integrity": "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==", "dev": true }, "@asamuzakjp/css-color": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.1.tgz", - "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.0.1.tgz", + "integrity": "sha512-2SZFvqMyvboVV1d15lMf7XiI3m7SDqXUuKaTymJYLN6dSGadqp+fVojqJlVoMlbZnlTmu3S0TLwLTJpvBMO1Aw==", "dev": true, "requires": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "lru-cache": "^11.2.4" + "@csstools/css-calc": "^3.1.1", + "@csstools/css-color-parser": "^4.0.2", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.2.6" }, "dependencies": { "lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "dev": true } } }, "@asamuzakjp/dom-selector": { - "version": "6.7.6", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.6.tgz", - "integrity": "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", "dev": true, "requires": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.4" + "lru-cache": "^11.2.6" }, "dependencies": { "lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "dev": true } } @@ -14395,6 +14418,15 @@ "integrity": "sha512-RzahvqTkfpY2jsDxo8YItPX+/iZ6hbiikw1YhE0bA9EKBR5Og8Pa6FHn9PO9M0zaXRVsr0GFQLKbB/0rzy9SzA==", "dev": true }, + "@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "requires": { + "css-tree": "^3.0.0" + } + }, "@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -14402,45 +14434,45 @@ "dev": true }, "@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", "dev": true }, "@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.1.1.tgz", + "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", "dev": true, "requires": {} }, "@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.0.2.tgz", + "integrity": "sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==", "dev": true, "requires": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.1.1" } }, "@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", "dev": true, "requires": {} }, "@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.22.tgz", - "integrity": "sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw==", + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.28.tgz", + "integrity": "sha512-1NRf1CUBjnr3K7hu8BLxjQrKCxEe8FP/xmPTenAxCRZWVLbmGotkFvG9mfNpjA6k7Bw1bw4BilZq9cu19RA5pg==", "dev": true }, "@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", "dev": true }, "@deque/dot": { @@ -16370,21 +16402,21 @@ "dev": true }, "cssstyle": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.6.tgz", - "integrity": "sha512-legscpSpgSAeGEe0TNcai97DKt9Vd9AsAdOL7Uoetb52Ar/8eJm3LIa39qpv8wWzLFlNG4vVvppQM+teaMPj3A==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.1.0.tgz", + "integrity": "sha512-Ml4fP2UT2K3CUBQnVlbdV/8aFDdlY69E+YnwJM+3VUWl08S3J8c8aRuJqCkD9Py8DHZ7zNNvsfKl8psocHZEFg==", "dev": true, "requires": { - "@asamuzakjp/css-color": "^4.1.1", - "@csstools/css-syntax-patches-for-csstree": "^1.0.21", + "@asamuzakjp/css-color": "^5.0.0", + "@csstools/css-syntax-patches-for-csstree": "^1.0.28", "css-tree": "^3.1.0", - "lru-cache": "^11.2.4" + "lru-cache": "^11.2.6" }, "dependencies": { "lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "dev": true } } @@ -16412,13 +16444,13 @@ "dev": true }, "data-urls": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", - "integrity": "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", "dev": true, "requires": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.0.0" + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" } }, "date-format": { @@ -19043,16 +19075,17 @@ } }, "jsdom": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.4.0.tgz", - "integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.1.0.tgz", + "integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==", "dev": true, "requires": { - "@acemir/cssom": "^0.9.28", - "@asamuzakjp/dom-selector": "^6.7.6", - "@exodus/bytes": "^1.6.0", - "cssstyle": "^5.3.4", - "data-urls": "^6.0.0", + "@acemir/cssom": "^0.9.31", + "@asamuzakjp/dom-selector": "^6.8.1", + "@bramus/specificity": "^2.4.2", + "@exodus/bytes": "^1.11.0", + "cssstyle": "^6.0.1", + "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", "http-proxy-agent": "^7.0.2", @@ -19062,11 +19095,11 @@ "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.0", + "undici": "^7.21.0", "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^8.0.0", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.1.0", - "ws": "^8.18.3", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0", "xml-name-validator": "^5.0.0" }, "dependencies": { @@ -22557,6 +22590,12 @@ "util-deprecate": "^1.0.2" } }, + "undici": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", + "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", + "dev": true + }, "undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", @@ -22742,9 +22781,9 @@ "dev": true }, "webidl-conversions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.0.tgz", - "integrity": "sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", "dev": true }, "websocket-driver": { @@ -22785,19 +22824,20 @@ } }, "whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", "dev": true }, "whatwg-url": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz", - "integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", "dev": true, "requires": { + "@exodus/bytes": "^1.11.0", "tr46": "^6.0.0", - "webidl-conversions": "^8.0.0" + "webidl-conversions": "^8.0.1" } }, "which": { diff --git a/package.json b/package.json index c5b7c3fb0..655745309 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "inquirer": "^8.2.5", "jquery": "^4.0.0", "jsdoc": "^4.0.2", - "jsdom": "^27.0.0", + "jsdom": "^28.1.0", "karma": "^6.4.1", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^3.1.1", From a09204f68f62579e36411661a33f667ca56db2ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:23:50 -0400 Subject: [PATCH 17/32] chore: bump the npm-low-risk group with 6 updates (#5020) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the npm-low-risk group with 6 updates: | Package | From | To | | --- | --- | --- | | [@axe-core/webdriverjs](https://github.com/dequelabs/axe-core-npm) | `4.11.0` | `4.11.1` | | [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) | `7.28.6` | `7.29.0` | | [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) | `7.28.6` | `7.29.0` | | [@babel/runtime-corejs3](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime-corejs3) | `7.28.6` | `7.29.0` | | [globals](https://github.com/sindresorhus/globals) | `17.2.0` | `17.3.0` | | [selenium-webdriver](https://github.com/SeleniumHQ/selenium) | `4.40.0` | `4.41.0` | Updates `@axe-core/webdriverjs` from 4.11.0 to 4.11.1
Release notes

Sourced from @​axe-core/webdriverjs's releases.

Release 4.11.1

Bug Fixes

Changelog

Sourced from @​axe-core/webdriverjs's changelog.

4.11.1 (2026-01-09)

Bug Fixes

Commits
Maintainer changes

This version was pushed to npm by [GitHub Actions](https://www.npmjs.com/~GitHub Actions), a new releaser for @​axe-core/webdriverjs since your current version.


Updates `@babel/core` from 7.28.6 to 7.29.0
Release notes

Sourced from @​babel/core's releases.

v7.29.0 (2026-01-31)

Thanks @​simbahax for your first PR!

:rocket: New Feature

  • babel-types
  • babel-standalone

:bug: Bug Fix

  • babel-parser
  • babel-traverse
    • #17708 fix(traverse): provide a hub when traversing a File or Program and no parentPath is given (@​simbahax)
  • babel-plugin-transform-block-scoping, babel-traverse
    • #17737 [7.x backport] fix: Rename switch discriminant references when body creates shadowing variable (@​magic-akari)

:running_woman: Performance

Committers: 6

Commits

Updates `@babel/preset-env` from 7.28.6 to 7.29.0
Release notes

Sourced from @​babel/preset-env's releases.

v7.29.0 (2026-01-31)

Thanks @​simbahax for your first PR!

:rocket: New Feature

  • babel-types
  • babel-standalone

:bug: Bug Fix

  • babel-parser
  • babel-traverse
    • #17708 fix(traverse): provide a hub when traversing a File or Program and no parentPath is given (@​simbahax)
  • babel-plugin-transform-block-scoping, babel-traverse
    • #17737 [7.x backport] fix: Rename switch discriminant references when body creates shadowing variable (@​magic-akari)

:running_woman: Performance

Committers: 6

Commits

Updates `@babel/runtime-corejs3` from 7.28.6 to 7.29.0
Release notes

Sourced from @​babel/runtime-corejs3's releases.

v7.29.0 (2026-01-31)

Thanks @​simbahax for your first PR!

:rocket: New Feature

  • babel-types
  • babel-standalone

:bug: Bug Fix

  • babel-parser
  • babel-traverse
    • #17708 fix(traverse): provide a hub when traversing a File or Program and no parentPath is given (@​simbahax)
  • babel-plugin-transform-block-scoping, babel-traverse
    • #17737 [7.x backport] fix: Rename switch discriminant references when body creates shadowing variable (@​magic-akari)

:running_woman: Performance

Committers: 6

Commits

Updates `globals` from 17.2.0 to 17.3.0
Release notes

Sourced from globals's releases.

v17.3.0

  • Update globals (2026-02-01) (#336) 295fba9

https://github.com/sindresorhus/globals/compare/v17.2.0...v17.3.0

Commits

Updates `selenium-webdriver` from 4.40.0 to 4.41.0
Release notes

Sourced from selenium-webdriver's releases.

Selenium 4.41.0

Detailed Changelogs by Component

Java     |     Python     |     DotNet     |     Ruby     |     JavaScript

What's Changed

... (truncated)

Commits
  • 9fc754f [build] Prepare for release of selenium-4.41.0 (#17098)
  • d5f22ec [java] mark tests passing in latest chrome beta
  • 89c5993 [build] fix auto-updating of browsers
  • 4592f1b [build] ci-python jobs not currently matching by default
  • 755d44c [build] put cdp version support in changelogs
  • 9aff5c7 [build] cannot invoke a rake task twice by default
  • 3a680a3 [build] ignore the staging branch for the PR and apply all patches in order
  • 20de9b9 [build] stage changes to an ephemeral staging branch since not all updates ar...
  • aac9a28 [py] Update test to check it's an integer rather than a value (#17114)
  • 02ec15f [rb] Update dependencies (#17111)
  • Additional commits viewable in compare view

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-automerge-start) [//]: # (dependabot-automerge-end) ---
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 ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stephen Mathieson <571265+stephenmathieson@users.noreply.github.com> --- package-lock.json | 449 ++++++++++++++++++++++++---------------------- 1 file changed, 234 insertions(+), 215 deletions(-) diff --git a/package-lock.json b/package-lock.json index 593201387..a5bea7637 100644 --- a/package-lock.json +++ b/package-lock.json @@ -152,12 +152,12 @@ "dev": true }, "node_modules/@axe-core/webdriverjs": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@axe-core/webdriverjs/-/webdriverjs-4.11.0.tgz", - "integrity": "sha512-Qt9DWcCQIPU9TMfCQnibFn0JDuvoSzfGs4nZM7LJeae/i3bpZ5qqLjc94U09BUneYQjTicfwHlKTcr9mmAb2cg==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@axe-core/webdriverjs/-/webdriverjs-4.11.1.tgz", + "integrity": "sha512-UVq7uBsqaQlHj7PQPg+WhE0nV6ccYtE0cnGglStS5RE3RAB+gQcb30R1k3usI+Q/xyROSJHhusOus4BzqrlZ1w==", "dev": true, "dependencies": { - "axe-core": "~4.11.0" + "axe-core": "~4.11.1" }, "peerDependencies": { "selenium-webdriver": ">3.0.0-beta || >=2.53.1 || >4.0.0-alpha" @@ -187,20 +187,20 @@ } }, "node_modules/@babel/core": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", - "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.28.6", + "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -314,25 +314,25 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz", + "integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" + "resolve": "^1.22.11" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "dependencies": { "ms": "^2.1.3" @@ -1123,15 +1123,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", + "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.5" + "@babel/traverse": "^7.29.0" }, "engines": { "node": ">=6.9.0" @@ -1158,14 +1158,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1544,12 +1543,12 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.6.tgz", - "integrity": "sha512-GaTI4nXDrs7l0qaJ6Rg06dtOXTBCG6TMDB44zbqofCIC4PqC7SEvmFFtpxzCDw9W5aJ7RKVshgXTLvLdBFV/qw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", + "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.28.6", + "@babel/compat-data": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", @@ -1563,7 +1562,7 @@ "@babel/plugin-syntax-import-attributes": "^7.28.6", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.6", + "@babel/plugin-transform-async-generator-functions": "^7.29.0", "@babel/plugin-transform-async-to-generator": "^7.28.6", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.6", @@ -1574,7 +1573,7 @@ "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.28.6", "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.28.6", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.6", "@babel/plugin-transform-exponentiation-operator": "^7.28.6", @@ -1587,9 +1586,9 @@ "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.28.6", - "@babel/plugin-transform-modules-systemjs": "^7.28.5", + "@babel/plugin-transform-modules-systemjs": "^7.29.0", "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", "@babel/plugin-transform-numeric-separator": "^7.28.6", @@ -1601,7 +1600,7 @@ "@babel/plugin-transform-private-methods": "^7.28.6", "@babel/plugin-transform-private-property-in-object": "^7.28.6", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.6", + "@babel/plugin-transform-regenerator": "^7.29.0", "@babel/plugin-transform-regexp-modifiers": "^7.28.6", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", @@ -1614,10 +1613,10 @@ "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "core-js-compat": "^3.43.0", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", "semver": "^6.3.1" }, "engines": { @@ -1642,12 +1641,12 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.6.tgz", - "integrity": "sha512-kz2fAQ5UzjV7X7D3ySxmj3vRq89dTpqOZWv76Z6pNPztkwb/0Yj1Mtx1xFrYj6mbIHysxtBot8J4o0JLCblcFw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.0.tgz", + "integrity": "sha512-TgUkdp71C9pIbBcHudc+gXZnihEDOjUAmXO1VO4HHGES7QLZcShR0stfKIxLSNIYx2fqhmJChOjm/wkF8wv4gA==", "dev": true, "dependencies": { - "core-js-pure": "^3.43.0" + "core-js-pure": "^3.48.0" }, "engines": { "node": ">=6.9.0" @@ -2786,9 +2785,9 @@ "dev": true }, "node_modules/axe-core": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.0.tgz", - "integrity": "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz", + "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==", "dev": true, "engines": { "node": ">=4" @@ -2806,13 +2805,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz", + "integrity": "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.6", "semver": "^6.3.1" }, "peerDependencies": { @@ -2820,25 +2819,25 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz", + "integrity": "sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" + "@babel/helper-define-polyfill-provider": "^0.6.6", + "core-js-compat": "^3.48.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz", + "integrity": "sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" + "@babel/helper-define-polyfill-provider": "^0.6.6" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -2879,6 +2878,18 @@ "node": "^4.5.0 || >= 5.9" } }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -3066,9 +3077,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.25.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", - "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -3085,10 +3096,11 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001726", - "electron-to-chromium": "^1.5.173", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.3" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -3233,9 +3245,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001731", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", - "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", + "version": "1.0.30001775", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001775.tgz", + "integrity": "sha512-s3Qv7Lht9zbVKE9XoTyRG6wVDCKdtOFIjBGg3+Yhn6JaytuNKPIjBMTMIY1AnOH3seL5mvF+x33oGAyK3hVt3A==", "dev": true, "funding": [ { @@ -4246,12 +4258,12 @@ } }, "node_modules/core-js-compat": { - "version": "3.44.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.44.0.tgz", - "integrity": "sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA==", + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.48.0.tgz", + "integrity": "sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==", "dev": true, "dependencies": { - "browserslist": "^4.25.1" + "browserslist": "^4.28.1" }, "funding": { "type": "opencollective", @@ -4259,9 +4271,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.44.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.44.0.tgz", - "integrity": "sha512-gvMQAGB4dfVUxpYD0k3Fq8J+n5bB6Ytl15lqlZrOIXFzxOhtPaObfkQGHtMRdyjIf7z2IeNULwi1jEwyS+ltKQ==", + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.48.0.tgz", + "integrity": "sha512-1slJgk89tWC51HQ1AEqG+s2VuwpTRr8ocu4n20QUcH1v9lAN0RXen0Q0AABa/DK1I7RrNWLucplOHMx8hfTGTw==", "dev": true, "hasInstallScript": true, "funding": { @@ -4875,9 +4887,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.5.194", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz", - "integrity": "sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA==", + "version": "1.5.302", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", + "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", "dev": true }, "node_modules/emoji-regex": { @@ -6377,9 +6389,9 @@ } }, "node_modules/globals": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.2.0.tgz", - "integrity": "sha512-tovnCz/fEq+Ripoq+p/gN1u7l6A7wwkoBT9pRCzTHzsD/LvADIzXZdjmRymh5Ztf0DYC3Rwg5cZRYjxzBmzbWg==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.3.0.tgz", + "integrity": "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==", "dev": true, "engines": { "node": ">=18" @@ -9629,9 +9641,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true }, "node_modules/nopt": { @@ -11157,12 +11169,12 @@ } }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -11332,9 +11344,9 @@ "dev": true }, "node_modules/selenium-webdriver": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.40.0.tgz", - "integrity": "sha512-dU0QbnVKdPmoNP8OtMCazRdtU2Ux6Wl4FEpG1iwUbDeajJK1dBAywBLrC1D7YFRtogHzN96AbXBgBAJaarcysw==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.41.0.tgz", + "integrity": "sha512-1XxuKVhr9az24xwixPBEDGSZP+P0z3ZOnCmr9Oiep0MlJN2Mk+flIjD3iBS9BgyjS4g14dikMqnrYUPIjhQBhA==", "dev": true, "funding": [ { @@ -11350,7 +11362,7 @@ "@bazel/runfiles": "^6.5.0", "jszip": "^3.10.1", "tmp": "^0.2.5", - "ws": "^8.18.3" + "ws": "^8.19.0" }, "engines": { "node": ">= 20.0.0" @@ -12724,9 +12736,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -13119,9 +13131,9 @@ "dev": true }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "dev": true, "engines": { "node": ">=10.0.0" @@ -13385,12 +13397,12 @@ "dev": true }, "@axe-core/webdriverjs": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@axe-core/webdriverjs/-/webdriverjs-4.11.0.tgz", - "integrity": "sha512-Qt9DWcCQIPU9TMfCQnibFn0JDuvoSzfGs4nZM7LJeae/i3bpZ5qqLjc94U09BUneYQjTicfwHlKTcr9mmAb2cg==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@axe-core/webdriverjs/-/webdriverjs-4.11.1.tgz", + "integrity": "sha512-UVq7uBsqaQlHj7PQPg+WhE0nV6ccYtE0cnGglStS5RE3RAB+gQcb30R1k3usI+Q/xyROSJHhusOus4BzqrlZ1w==", "dev": true, "requires": { - "axe-core": "~4.11.0" + "axe-core": "~4.11.1" } }, "@babel/code-frame": { @@ -13411,20 +13423,20 @@ "dev": true }, "@babel/core": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", - "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "requires": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.28.6", + "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -13512,22 +13524,22 @@ } }, "@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz", + "integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==", "dev": true, "requires": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" + "resolve": "^1.22.11" }, "dependencies": { "debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "requires": { "ms": "^2.1.3" @@ -14026,15 +14038,15 @@ } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", + "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.5" + "@babel/traverse": "^7.29.0" } }, "@babel/plugin-transform-modules-umd": { @@ -14048,13 +14060,13 @@ } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-new-target": { @@ -14279,12 +14291,12 @@ } }, "@babel/preset-env": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.6.tgz", - "integrity": "sha512-GaTI4nXDrs7l0qaJ6Rg06dtOXTBCG6TMDB44zbqofCIC4PqC7SEvmFFtpxzCDw9W5aJ7RKVshgXTLvLdBFV/qw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", + "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", "dev": true, "requires": { - "@babel/compat-data": "^7.28.6", + "@babel/compat-data": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", @@ -14298,7 +14310,7 @@ "@babel/plugin-syntax-import-attributes": "^7.28.6", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.6", + "@babel/plugin-transform-async-generator-functions": "^7.29.0", "@babel/plugin-transform-async-to-generator": "^7.28.6", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.6", @@ -14309,7 +14321,7 @@ "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.28.6", "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.28.6", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.6", "@babel/plugin-transform-exponentiation-operator": "^7.28.6", @@ -14322,9 +14334,9 @@ "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.28.6", - "@babel/plugin-transform-modules-systemjs": "^7.28.5", + "@babel/plugin-transform-modules-systemjs": "^7.29.0", "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", "@babel/plugin-transform-numeric-separator": "^7.28.6", @@ -14336,7 +14348,7 @@ "@babel/plugin-transform-private-methods": "^7.28.6", "@babel/plugin-transform-private-property-in-object": "^7.28.6", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.6", + "@babel/plugin-transform-regenerator": "^7.29.0", "@babel/plugin-transform-regexp-modifiers": "^7.28.6", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", @@ -14349,10 +14361,10 @@ "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "core-js-compat": "^3.43.0", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", "semver": "^6.3.1" } }, @@ -14368,12 +14380,12 @@ } }, "@babel/runtime-corejs3": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.6.tgz", - "integrity": "sha512-kz2fAQ5UzjV7X7D3ySxmj3vRq89dTpqOZWv76Z6pNPztkwb/0Yj1Mtx1xFrYj6mbIHysxtBot8J4o0JLCblcFw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.0.tgz", + "integrity": "sha512-TgUkdp71C9pIbBcHudc+gXZnihEDOjUAmXO1VO4HHGES7QLZcShR0stfKIxLSNIYx2fqhmJChOjm/wkF8wv4gA==", "dev": true, "requires": { - "core-js-pure": "^3.43.0" + "core-js-pure": "^3.48.0" } }, "@babel/template": { @@ -15214,9 +15226,9 @@ "dev": true }, "axe-core": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.0.tgz", - "integrity": "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz", + "integrity": "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==", "dev": true }, "axios": { @@ -15231,33 +15243,33 @@ } }, "babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz", + "integrity": "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==", "dev": true, "requires": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.6", "semver": "^6.3.1" } }, "babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz", + "integrity": "sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" + "@babel/helper-define-polyfill-provider": "^0.6.6", + "core-js-compat": "^3.48.0" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz", + "integrity": "sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.6.5" + "@babel/helper-define-polyfill-provider": "^0.6.6" } }, "balanced-match": { @@ -15278,6 +15290,12 @@ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "dev": true }, + "baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true + }, "basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -15449,15 +15467,16 @@ "dev": true }, "browserslist": { - "version": "4.25.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", - "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001726", - "electron-to-chromium": "^1.5.173", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.3" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" } }, "buffer": { @@ -15554,9 +15573,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001731", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", - "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", + "version": "1.0.30001775", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001775.tgz", + "integrity": "sha512-s3Qv7Lht9zbVKE9XoTyRG6wVDCKdtOFIjBGg3+Yhn6JaytuNKPIjBMTMIY1AnOH3seL5mvF+x33oGAyK3hVt3A==", "dev": true }, "catharsis": { @@ -16319,18 +16338,18 @@ "dev": true }, "core-js-compat": { - "version": "3.44.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.44.0.tgz", - "integrity": "sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA==", + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.48.0.tgz", + "integrity": "sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==", "dev": true, "requires": { - "browserslist": "^4.25.1" + "browserslist": "^4.28.1" } }, "core-js-pure": { - "version": "3.44.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.44.0.tgz", - "integrity": "sha512-gvMQAGB4dfVUxpYD0k3Fq8J+n5bB6Ytl15lqlZrOIXFzxOhtPaObfkQGHtMRdyjIf7z2IeNULwi1jEwyS+ltKQ==", + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.48.0.tgz", + "integrity": "sha512-1slJgk89tWC51HQ1AEqG+s2VuwpTRr8ocu4n20QUcH1v9lAN0RXen0Q0AABa/DK1I7RrNWLucplOHMx8hfTGTw==", "dev": true }, "core-util-is": { @@ -16787,9 +16806,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.5.194", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz", - "integrity": "sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA==", + "version": "1.5.302", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", + "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", "dev": true }, "emoji-regex": { @@ -17914,9 +17933,9 @@ } }, "globals": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.2.0.tgz", - "integrity": "sha512-tovnCz/fEq+Ripoq+p/gN1u7l6A7wwkoBT9pRCzTHzsD/LvADIzXZdjmRymh5Ztf0DYC3Rwg5cZRYjxzBmzbWg==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.3.0.tgz", + "integrity": "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==", "dev": true }, "globule": { @@ -20308,9 +20327,9 @@ } }, "node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true }, "nopt": { @@ -21469,12 +21488,12 @@ } }, "resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "requires": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -21602,15 +21621,15 @@ "dev": true }, "selenium-webdriver": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.40.0.tgz", - "integrity": "sha512-dU0QbnVKdPmoNP8OtMCazRdtU2Ux6Wl4FEpG1iwUbDeajJK1dBAywBLrC1D7YFRtogHzN96AbXBgBAJaarcysw==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.41.0.tgz", + "integrity": "sha512-1XxuKVhr9az24xwixPBEDGSZP+P0z3ZOnCmr9Oiep0MlJN2Mk+flIjD3iBS9BgyjS4g14dikMqnrYUPIjhQBhA==", "dev": true, "requires": { "@bazel/runfiles": "^6.5.0", "jszip": "^3.10.1", "tmp": "^0.2.5", - "ws": "^8.18.3" + "ws": "^8.19.0" } }, "semver": { @@ -22658,9 +22677,9 @@ "dev": true }, "update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "requires": { "escalade": "^3.2.0", @@ -22953,9 +22972,9 @@ "dev": true }, "ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "dev": true, "requires": {} }, From 3d80a37873248b9573738bc4990eb3a59f0a2154 Mon Sep 17 00:00:00 2001 From: Dylan Barrell Date: Thu, 19 Mar 2026 16:14:44 -0400 Subject: [PATCH 18/32] chore: add CLAUDE.md and pull request checklist (#5035) Adds a CLAUDE.md file for contributors --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Jonathan Garbee --- CLAUDE.md | 102 ++++++++++++++++++ doc/examples/code-patterns.md | 152 +++++++++++++++++++++++++++ doc/examples/pr-review-patterns.md | 69 ++++++++++++ doc/examples/rule-check-templates.md | 112 ++++++++++++++++++++ doc/examples/test-patterns.md | 94 +++++++++++++++++ doc/pull-request-checklist.md | 42 ++++++++ 6 files changed, 571 insertions(+) create mode 100644 CLAUDE.md create mode 100644 doc/examples/code-patterns.md create mode 100644 doc/examples/pr-review-patterns.md create mode 100644 doc/examples/rule-check-templates.md create mode 100644 doc/examples/test-patterns.md create mode 100644 doc/pull-request-checklist.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..8a81ac332 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,102 @@ +# axe-core — Claude Code Context + +**Last updated:** 2026-03-19 + +## 0. Fundamental Standards + +- **Formatting:** Run `npm run fmt` (Prettier) and `npm run eslint` before every commit. No exceptions. +- **Zero-Exception Testing:** 100% coverage goal. Run `npm test` before completion. `feat`/`fix` and other behavior-changing PRs require unit + integration tests where applicable; see `doc/code-submission-guidelines.md` for exceptions (e.g., some `chore`/docs changes). +- **Import Rule:** Directory-level import restrictions are strictly enforced. See `eslint.config.js`. +- **Commits:** Angular commit convention is mandatory. PRs with non-conforming commits will be rejected. See `doc/code-submission-guidelines.md`. +- **Issues:** All unresolved issues tracked in [GitHub Issues](https://github.com/dequelabs/axe-core/issues). + +## 1. Technical Guidelines + +### Code Structure + +- **Return Early:** Keep the happy path left-aligned. Handle errors/edge cases first with early returns — never nest when you can exit. +- **Exports:** Default export at the top of the file, immediately after imports. +- **JSDoc:** Add JSDoc/DocBlock comments where appropriate, especially for exported APIs and complex logic. Document parameters and return types. See `doc/code-submission-guidelines.md` (source of truth) and `doc/developer-guide.md` for additional guidance. +- **Naming:** Files and rule/check IDs in kebab-case. Functions in camelCase. Booleans prefixed `is`/`has`/`should`. Constants in `UPPER_SNAKE_CASE`. +- **Variables:** Declare at point of use, not at the top of the function. + +### Virtual Nodes vs. HTMLElement + +- **Prefer Virtual Nodes** for attribute access and property reads (`virtualNode.attr()`, `virtualNode.props`). +- **Use real DOM** only when you need DOM APIs (e.g., `getBoundingClientRect`, `getRootNode`). +- **`core/utils/` functions** should default to real DOM inputs/outputs, except utilities that are explicitly documented as operating on `VirtualNode` (for example, tree or selector helpers). Avoid introducing new `VirtualNode`-dependent utilities unless there is a clear performance or API benefit. +- **Conversion:** Use `getNodeFromTree()` from `core/utils` when you receive an ambiguous input (such as a `VirtualNode`, selector, or mixed type) and need to resolve it to a real DOM `Node`. + +### Import Restrictions (Hard Rules) + +- `standards/` → nothing (pure data, no imports). +- `core/utils/` → other `core/utils`, `core/base`, `standards` via **direct file paths only** (no index). +- `core/imports/` → node modules **only** (the only place npm imports are allowed). +- `commons/` → other `commons` (direct paths), `core/utils` (index OK). +- `checks/` and `rules/` → any directory (index OK). +- **Never** import `commons` from `core/utils`. This is the most commonly rejected violation. + +### Checks & Rules + +- **Check evaluate functions:** Return `true` (pass), `false` (fail), or `undefined` (incomplete). Use `this.data()` to pass values to message templates and to provide incomplete-result detail. +- **Rule JSON:** Use `all`, `any`, `none` check arrays. `selector` + optional `matches` to scope candidates. Valid `impact` values: `"minor"`, `"moderate"`, `"serious"`, `"critical"`. +- **Standards data:** Never hardcode ARIA/HTML lists in checks. Query from `standards/` via `commons/standards` functions. +- **Messages:** All user-facing strings live in check/rule JSON `metadata.messages`. Use `${data.property}` templates. Support singular/plural variants. Update `locales/_template.json` whenever messages change (auto-synced on `npm run build`). + +### High-Risk Areas (Extra Scrutiny Required) + +- **Color contrast:** Handles all CSS color formats, opacity, blend modes, stacking contexts, text-shadow. Return `undefined` when background cannot be determined. See `doc/developer-guide.md`. +- **ARIA validation:** Must stay current with spec. Query roles/attrs from `standards/aria-roles.js` and `standards/aria-attrs.js`. Handle implicit vs. explicit roles. See `doc/rule-development.md`. +- **Hidden elements:** Use `isVisibleToScreenReaders()`, not CSS visibility alone. Account for `aria-hidden="true"` and Shadow DOM boundaries. +- **i18n:** Update `locales/_template.json` on every message change and commit the generated file alongside source. + +## 2. Testing + +- **Structure:** Mirror `lib/` exactly under `test/`. File `lib/commons/text/sanitize.js` → `test/commons/text/sanitize.js`. +- **Checks:** Use `axe.testUtils.MockCheckContext()`. Only reset `checkContext` in `afterEach` — `fixture` and `axe._tree` are auto-cleared. +- **Integration tests:** All rule changes require an HTML + JSON pair. Use `test/integration/rules//` for mocha-hosted tests or `test/integration/full//` when the rule requires a full HTML page. JSON selectors must use axe array format (`["#id"]`; iframes: `["iframe", "#id"]`). Also update or create virtual-rules tests where appropriate. +- **Shadow DOM:** Every relevant check/rule must include an open Shadow DOM test case using `queryShadowFixture`. +- **Logging:** Do not commit `console.log` statements. + +## 3. Build & Commits + +- **Bundles (`axe.js`, `axe.min.js`)** are auto-generated for releases/publishing and are not committed to the repo (they are gitignored). +- **Locales template (`locales/_template.json`)** is auto-generated. When message strings change, regenerate this file and commit it in the same commit as the source changes — never in a separate commit. +- **One change per PR.** Do not mix refactoring with feature work. +- **Commit format:** `(): ` — imperative, lowercase, no period, ≤100 chars total. Body explains motivation. Footer: `Closes issue #123` or full URL. See `doc/code-submission-guidelines.md` for the full type list. + +**Example:** + +``` +fix(aria-valid-attr-value): handle multiple aria-errormessage IDs + +When aria-errormessage contains multiple space-separated IDs, verify +all IDs exist in aria-describedby instead of matching the full string. + +Closes issue #4957 +``` + +## 4. Documentation & API Changes + +- **New rules:** Update `CHANGELOG.md`. `doc/rule-descriptions.md` is auto-generated by `npm run build`. +- **API changes:** Update `doc/API.md` and `axe.d.ts` TypeScript definitions. +- **Breaking changes:** Avoid breaking changes — prefer supporting both old and new formats simultaneously. If unavoidable, add `BREAKING CHANGE: description` to commit footer, include migration guide in `CHANGELOG.md`, and tag deprecated code with `@deprecated` JSDoc. + +## 5. Examples (Copy-Paste Reference) + +- **Code patterns:** `doc/examples/code-patterns.md` — return early, default export, imports, JSDoc, Virtual Node usage +- **Test patterns:** `doc/examples/test-patterns.md` — unit tests, check tests, Shadow DOM tests, integration test HTML+JSON +- **Rule & check templates:** `doc/examples/rule-check-templates.md` — JSON templates for rules and checks, evaluate function pattern +- **PR review patterns:** `doc/examples/pr-review-patterns.md` — common reviewer feedback, anti-patterns, what reviewers look for + +## 6. Reference Docs & Help + +- **Contributing guide:** `CONTRIBUTING.md` +- **Import rules detail:** `eslint.config.js` +- **Code submission standards:** `doc/code-submission-guidelines.md` +- **Developer guide:** `doc/developer-guide.md` +- **Rule development:** `doc/rule-development.md` +- **API reference:** `doc/API.md` +- **Pull Request Checklist:** `doc/pull-request-checklist.md` +- **Slack:** [axe-community](https://accessibility.deque.com/axe-community) +- **Issues:** [GitHub Issues](https://github.com/dequelabs/axe-core/issues) diff --git a/doc/examples/code-patterns.md b/doc/examples/code-patterns.md new file mode 100644 index 000000000..e342b8f1e --- /dev/null +++ b/doc/examples/code-patterns.md @@ -0,0 +1,152 @@ +# Code Pattern Examples + +Quick-reference examples for axe-core coding conventions. + +## Default Export at Top + +```javascript +// GOOD: Default export right after imports +import { getRole } from '../../commons/aria'; +import { isVisible } from '../../commons/dom'; + +export default function myFunction(node, options) { + // function body +} + +// BAD: Export buried at bottom of file +import { getRole } from '../../commons/aria'; + +function myFunction(node, options) { + // body +} + +// ... more code ... + +export default myFunction; // Too far from top +``` + +## Return Early Pattern + +```javascript +// GOOD: Main path left-aligned, edge cases exit early +export default function processValue(value) { + if (!value) { + return null; + } + + if (value.length < 3) { + throw new Error('Value too short'); + } + + const normalized = normalize(value); + const result = transform(normalized); + return result; +} + +// BAD: Nested conditionals +export default function processValue(value) { + let result; + if (value) { + if (value.length >= 3) { + const normalized = normalize(value); + result = transform(normalized); + } else { + throw new Error('Value too short'); + } + } else { + result = null; + } + return result; +} +``` + +## Import Restrictions + +```javascript +// GOOD: commons importing from core/utils via index +import { getNodeFromTree } from '../../core/utils'; + +// GOOD: commons importing other commons directly +import getExplicitRole from '../aria/get-explicit-role'; + +// BAD: core/utils importing from commons — NEVER DO THIS +import { isDisabled } from '../../commons/forms'; + +// BAD: importing from index in core/utils — use direct path +import { someUtil } from './index'; // Use: import someUtil from './some-util'; +``` + +## JSDoc Comments + +### Standard function + +```javascript +/** + * Determines if an element is a native select element + * @method isNativeSelect + * @memberof axe.commons.forms + * @param {VirtualNode|Element} node Node to determine if select + * @returns {Boolean} + */ +import nodeLookup from '../../core/utils/node-lookup'; + +function isNativeSelect(node) { + const { vNode } = nodeLookup(node); + const nodeName = vNode.props.nodeName; + return nodeName === 'select'; +} +``` + +### Check evaluate function + +```javascript +/** + * Check if an element's `role` attribute uses any abstract role values. + * + * Abstract roles are taken from the `ariaRoles` standards object from the roles `type` property. + * + * ##### Data: + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TypeDescription
String[]List of all abstract roles
+ * + * @memberof checks + * @return {Boolean} True if the element uses an `abstract` role. False otherwise. + */ +function abstractroleEvaluate(node, options, virtualNode) { + // implementation +} +``` + +## Virtual Node vs HTMLElement + +```javascript +// Use Virtual Node for attribute access and property reads +function myCheck(node, options, virtualNode) { + const role = virtualNode.attr('role'); // Cached attribute access + const nodeName = virtualNode.props.nodeName; + + // Only access real node when you need DOM APIs + const rect = node.getBoundingClientRect(); + const rootNode = node.getRootNode(); +} + +// Convert ambiguous input using nodeLookup +import nodeLookup from '../../core/utils/node-lookup'; + +function myFunction(nodeOrVirtual) { + const { vNode, domNode } = nodeLookup(nodeOrVirtual); + // vNode = VirtualNode, domNode = real DOM node +} +``` diff --git a/doc/examples/pr-review-patterns.md b/doc/examples/pr-review-patterns.md new file mode 100644 index 000000000..a56324054 --- /dev/null +++ b/doc/examples/pr-review-patterns.md @@ -0,0 +1,69 @@ +# PR Review Patterns + +Common feedback and anti-patterns observed in axe-core code reviews. + +## What Gets Called Out + +### 1. Missing Tests + +- Every behavior-changing code change needs unit tests +- Rule changes need integration tests (HTML + JSON pair) +- Shadow DOM test coverage required for relevant checks/rules + +### 2. Commit Message Format + +- Wrong type/scope +- Not imperative present tense +- Subject too long or capitalized +- Missing issue reference in footer + +### 3. Import Violations + +- `core/utils` importing from `commons` (forbidden) +- Using index imports where direct file paths are required +- Importing node modules outside `core/imports` + +### 4. Code Style Issues + +- Not using return early pattern +- Default export not at top of file +- Nested conditionals when early return would work +- Missing JSDoc comments + +### 5. Performance Concerns + +- Unnecessary DOM queries in loops +- Not caching Virtual Node properties +- Computing same value repeatedly instead of storing it + +### 6. Incomplete Results + +- Not returning `undefined` when a check can't determine the result +- Missing `incomplete` message variants in check JSON +- Not setting appropriate `this.data()` for incomplete cases + +### 7. Accessibility Edge Cases + +- Not considering all ARIA states +- Missing edge cases for hidden elements +- Not handling Shadow DOM properly + +## What Reviewers Love + +1. Comprehensive test coverage including edge cases +2. Clear, detailed commit messages with motivation +3. JSDoc comments that explain "why" not just "what" +4. Performance-conscious code that caches appropriately +5. Following existing patterns in similar files +6. Integration tests that cover both pass and fail cases + +## Common PR Mistakes + +1. Not running `npm test` locally before pushing +2. Not committing auto-generated `locales/_template.json` in the same commit as message source changes +3. Changing multiple unrelated things in one PR — split refactoring from feature work +4. Not updating integration tests when changing rule behavior +5. `console.log` statements should not be committed +6. Not handling `null` or `undefined` gracefully +7. Hardcoding strings that should come from `standards/` data +8. Changing public APIs without `BREAKING CHANGE` in commit footer diff --git a/doc/examples/rule-check-templates.md b/doc/examples/rule-check-templates.md new file mode 100644 index 000000000..5bfd25109 --- /dev/null +++ b/doc/examples/rule-check-templates.md @@ -0,0 +1,112 @@ +# Rule & Check JSON Templates + +Quick-reference templates for creating axe-core rules and checks. + +## Rule JSON + +```json +{ + "id": "aria-input-field-name", + "impact": "serious", + "selector": "[role=\"textbox\"], [role=\"combobox\"]", + "matches": "no-naming-method-matches", + "tags": ["cat.aria", "wcag2a", "wcag412"], + "metadata": { + "description": "Ensure every ARIA input field has an accessible name", + "help": "ARIA input fields must have an accessible name" + }, + "all": [], + "any": ["aria-label", "aria-labelledby", "non-empty-title"], + "none": ["no-implicit-explicit-label"] +} +``` + +**Key properties:** + +| Property | Description | +| ----------- | ------------------------------------------------------------- | +| `selector` | CSS selector for candidate elements | +| `matches` | Optional function to further filter elements | +| `all` | All checks must pass | +| `any` | At least one check must pass | +| `none` | All checks must fail (for the rule to pass) | +| `impact` | `"minor"`, `"moderate"`, `"serious"`, `"critical"` | +| `enabled` | Defaults to `true`; set `false` for disabled/deprecated rules | +| `tags` | Grouping: `wcag2a`, `wcag2aa`, `best-practice`, `cat.*`, etc. | +| `pageLevel` | `true` if rule should only run on the top-level window | + +## Check JSON + +```json +{ + "id": "aria-allowed-attr", + "evaluate": "aria-allowed-attr-evaluate", + "options": { + "validTreeRowAttrs": ["aria-posinset", "aria-setsize"] + }, + "metadata": { + "impact": "critical", + "messages": { + "pass": "ARIA attributes are used correctly for the defined role", + "fail": { + "singular": "ARIA attribute is not allowed: ${data.values}", + "plural": "ARIA attributes are not allowed: ${data.values}" + }, + "incomplete": "Check that there is no problem if the ARIA attribute is ignored: ${data.values}" + } + } +} +``` + +**Message templates:** + +- Use `${data.property}` for dynamic values set via `this.data()` +- Support singular/plural variants via object with `singular`/`plural` keys +- `locales/_template.json` is auto-generated by `npm run build` — do not edit it manually, but commit the regenerated file alongside source changes + +## Check Evaluate Function + +```javascript +export default function myCheckEvaluate(node, options, virtualNode) { + // node: HTMLElement + // options: from check JSON or runtime config + // virtualNode: Virtual Node representation + + // Early returns for edge cases + if (someEdgeCase) { + return true; // Pass + } + + // Compute what you need + const relevantData = computeStuff(virtualNode); + + // Set data for messages (optional) + // this.data() sets an arbitrary object passed to message templates + if (relevantData.hasIssues) { + this.data({ + messageKey: 'someIssue', // Selects which message variant to use (e.g., singular/plural) + values: relevantData.issueList // ${data.values} in templates resolves arrays + }); + } + + // Return boolean or undefined + if (cannotDetermine) { + this.data({ reason: 'could not determine background color' }); + return undefined; // Incomplete + } + + return isValid; // true = pass, false = fail +} +``` + +**Return values:** + +- `true` — check passed +- `false` — check failed +- `undefined` — incomplete (cannot determine result) + +**`this.data()` usage:** + +- Sets an arbitrary data object that gets passed to message templates via `${data.propertyName}` +- `messageKey` — selects which message variant to use (e.g., `singular`/`plural`) +- Any other keys are available in templates as `${data.keyName}` — arrays are automatically joined diff --git a/doc/examples/test-patterns.md b/doc/examples/test-patterns.md new file mode 100644 index 000000000..e373ee0ce --- /dev/null +++ b/doc/examples/test-patterns.md @@ -0,0 +1,94 @@ +# Test Pattern Examples + +Quick-reference examples for axe-core test conventions. + +## Unit Test — Commons Function + +```javascript +describe('text.sanitize', function () { + it('should collapse whitespace and trim', function () { + assert.equal(axe.commons.text.sanitize('\thi\t'), 'hi'); + assert.equal(axe.commons.text.sanitize('\t\nhi \t'), 'hi'); + assert.equal(axe.commons.text.sanitize('hello\u00A0there'), 'hello there'); + }); + + it('should accept null', function () { + assert.equal(axe.commons.text.sanitize(null), ''); + }); +}); +``` + +## Unit Test — Check Evaluate + +```javascript +describe('aria-allowed-attr', function () { + const fixture = document.getElementById('fixture'); + const checkContext = axe.testUtils.MockCheckContext(); + + afterEach(function () { + checkContext.reset(); + }); + + it('should return true if all ARIA attributes are allowed', function () { + const vNode = queryFixture( + '
' + ); + + assert.isTrue( + axe.testUtils + .getCheckEvaluate('aria-allowed-attr') + .call(checkContext, vNode.actualNode, {}, vNode) + ); + }); +}); +``` + +## Shadow DOM Test + +```javascript +it('should work with Shadow DOM', function () { + const vNode = queryShadowFixture( + '
', + '
Test
' + ); + // Test your function against the shadow DOM content +}); +``` + +## Integration Test — Rule + +Each rule change requires an HTML + JSON pair in `test/integration/rules//` (mocha-hosted) or `test/integration/full//` (full HTML page). Virtual-rules tests in `test/virtual-rules/` should also be updated or created for appropriate rules. See sections below for details. + +### HTML file (`aria-allowed-attr.html`) + +```html +
Valid
+
Invalid
+``` + +### JSON file (`aria-allowed-attr.json`) + +```json +{ + "description": "aria-allowed-attr test", + "rule": "aria-allowed-attr", + "violations": [["#fail1"]], + "passes": [["#pass1"]] +} +``` + +IDs use axe selector array format. For elements inside iframes: + +```json +{ + "violations": [["iframe", "#fail-inside-iframe"]] +} +``` + +### Full-page integration tests + +For rules that need a complete HTML page (e.g., landmark rules, page-level rules), use `test/integration/full/` instead. These tests run against a full HTML document rather than injected fragments. + +### Virtual rules tests + +Rules that can run without a DOM (using only virtual nodes) should have tests in `test/virtual-rules/`. These tests verify that rules work correctly with `axe.run()` on serialized node data. diff --git a/doc/pull-request-checklist.md b/doc/pull-request-checklist.md new file mode 100644 index 000000000..c36a6e05d --- /dev/null +++ b/doc/pull-request-checklist.md @@ -0,0 +1,42 @@ +# axe-core — PR Checklist + +Complete all applicable items before opening a PR. For items that do not apply to this PR (for example, tests for a `chore`-only change), mark them as "N/A" and follow `doc/code-submission-guidelines.md`. Reviewers will not merge until all required boxes are checked. + +## Code + +- [ ] Default export is at the top of the file, immediately after imports +- [ ] Return early pattern used — no nested conditionals where an early return works +- [ ] DocBlock comments where appropriate (especially for public/exported APIs), per `doc/code-submission-guidelines.md` +- [ ] No `console.log` statements committed +- [ ] No hardcoded ARIA/HTML lists — queried from `standards/` via `commons/standards` +- [ ] Imports follow directory restrictions — especially no `commons` from `core/utils` + +## Tests + +- [ ] Unit tests cover all code paths (`null`/`undefined` input handling only needed for public API functions) +- [ ] Integration test HTML + JSON pair added/updated for any rule changes — use `integration/rules` for mocha-hosted tests or `integration/full` when the rule requires a full HTML page +- [ ] Virtual-rules tests updated or created for appropriate rules +- [ ] Shadow DOM test case added where relevant +- [ ] Code built with `npm run build` before testing +- [ ] All applicable tests pass locally: `npm test` (unit), `test:integration`, `test:virtual-rules`, `test:act`, `test:apg`, `test:examples`, `test:node`, `test:jsdom` + +## Formatting & Build + +- [ ] `npm run fmt` passes (Prettier) +- [ ] `npm run eslint` passes +- [ ] `npm run build` run — generated artifacts that are tracked in git (for example `locales/_template.json`) are committed in the same commit as source changes + +## Commits + +- [ ] All commits follow Angular format: `(): ` +- [ ] Subject is imperative, lowercase, no trailing period, ≤100 chars total +- [ ] Commit body explains motivation (not just what changed) +- [ ] Footer includes issue reference: `Closes issue: #123` or full URL +- [ ] Breaking changes avoided — prefer supporting both old and new formats simultaneously. If unavoidable, document in footer: `BREAKING CHANGE: description` + +## Docs + +- [ ] `doc/rule-descriptions.md` is auto-generated by `npm run build` — verify it regenerates correctly for new rules +- [ ] `doc/API.md` and `axe.d.ts` updated for API changes +- [ ] `locales/_template.json` updated if messages changed +- [ ] `CHANGELOG.md` updated with migration guide for breaking changes From cf8a3c039b121c0c64a1eb8805c586659b69f3c1 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Thu, 26 Mar 2026 10:06:12 -0600 Subject: [PATCH 19/32] fix(target-size): ignore widgets that are inline with other inline elements (#5000) Closes: https://github.com/dequelabs/axe-core/issues/4392 --------- Co-authored-by: Wilco Fiers Co-authored-by: Wilco Fiers --- lib/commons/dom/is-in-text-block.js | 87 +++-- lib/rules/widget-not-inline-matches.js | 3 +- test/commons/dom/is-in-text-block.js | 351 +++++++++++++----- .../rules/target-size/target-size.html | 30 +- .../rules/target-size/target-size.json | 1 + 5 files changed, 337 insertions(+), 135 deletions(-) diff --git a/lib/commons/dom/is-in-text-block.js b/lib/commons/dom/is-in-text-block.js index 3f4a4f39b..ecf1f6a77 100644 --- a/lib/commons/dom/is-in-text-block.js +++ b/lib/commons/dom/is-in-text-block.js @@ -1,37 +1,11 @@ import getComposedParent from './get-composed-parent'; import sanitize from '../text/sanitize'; -import { getNodeFromTree } from '../../core/utils'; +import { getNodeFromTree, nodeLookup } from '../../core/utils'; import getRoleType from '../aria/get-role-type'; -function walkDomNode(node, functor) { - if (functor(node.actualNode) !== false) { - node.children.forEach(child => walkDomNode(child, functor)); - } -} +const blockLike = ['block', 'list-item', 'table', 'flex', 'grid']; -const blockLike = [ - 'block', - 'list-item', - 'table', - 'flex', - 'grid', - 'inline-block' -]; - -function isBlock(elm) { - const display = window.getComputedStyle(elm).getPropertyValue('display'); - return blockLike.includes(display) || display.substr(0, 6) === 'table-'; -} - -function getBlockParent(node) { - // Find the closest parent - let parentBlock = getComposedParent(node); - while (parentBlock && !isBlock(parentBlock)) { - parentBlock = getComposedParent(parentBlock); - } - - return getNodeFromTree(parentBlock); -} +const inlineBlockLike = ['inline-block', 'inline-flex', 'inline-grid']; /** * Determines if an element is within a text block @@ -41,16 +15,21 @@ function getBlockParent(node) { * @param {Element} node [description] * @param {Object} options Optional * @property {Bool} noLengthCompare + * @property {Bool} includeInlineBlock * @return {Boolean} [description] */ -function isInTextBlock(node, options) { - if (isBlock(node)) { - // Ignore if the link is a block +function isInTextBlock( + node, + { noLengthCompare, includeInlineBlock = false } = {} +) { + const { vNode, domNode } = nodeLookup(node); + if (isBlock(domNode) || (!includeInlineBlock && isInlineBlockLike(vNode))) { + // Ignore if the element is a block return false; } // Find all the text part of the parent block not in a link, and all the text in a link - const virtualParent = getBlockParent(node); + const virtualParent = getBlockParent(domNode); let parentText = ''; let widgetText = ''; let inBrBlock = 0; @@ -58,6 +37,10 @@ function isInTextBlock(node, options) { // We want to ignore hidden text, and if br / hr is used, only use the section of the parent // that has the link we're looking at walkDomNode(virtualParent, currNode => { + if (currNode === virtualParent.actualNode) { + return true; // Skip the element itself + } + // We're already passed it, skip everything else if (inBrBlock === 2) { return false; @@ -73,11 +56,12 @@ function isInTextBlock(node, options) { } const nodeName = (currNode.nodeName || '').toUpperCase(); - if (currNode === node) { + if (currNode === domNode) { inBrBlock = 1; } + const nodeIsBlock = isBlock(currNode); // BR and HR elements break the line - if (['BR', 'HR'].includes(nodeName)) { + if (nodeIsBlock || ['BR', 'HR'].includes(nodeName)) { if (inBrBlock === 0) { parentText = ''; widgetText = ''; @@ -86,7 +70,9 @@ function isInTextBlock(node, options) { } // Don't walk nodes with content not displayed on screen. - } else if ( + } + if ( + nodeIsBlock || currNode.style.display === 'none' || currNode.style.overflow === 'hidden' || !['', null, 'none'].includes(currNode.style.float) || @@ -103,7 +89,7 @@ function isInTextBlock(node, options) { }); parentText = sanitize(parentText); - if (options?.noLengthCompare) { + if (noLengthCompare) { return parentText.length !== 0; } @@ -112,3 +98,30 @@ function isInTextBlock(node, options) { } export default isInTextBlock; + +function isBlock(node) { + const { vNode } = nodeLookup(node); + const display = vNode.getComputedStylePropertyValue('display'); + return blockLike.includes(display) || display.substr(0, 6) === 'table-'; +} + +function isInlineBlockLike(vNode) { + const display = vNode.getComputedStylePropertyValue('display'); + return inlineBlockLike.includes(display); +} + +function walkDomNode(node, functor) { + if (functor(node.actualNode) !== false) { + node.children.forEach(child => walkDomNode(child, functor)); + } +} + +function getBlockParent(node) { + // Find the closest parent + let parentBlock = getComposedParent(node); + while (parentBlock && !isBlock(parentBlock)) { + parentBlock = getComposedParent(parentBlock); + } + + return getNodeFromTree(parentBlock); +} diff --git a/lib/rules/widget-not-inline-matches.js b/lib/rules/widget-not-inline-matches.js index 61e5f2270..14b1036ef 100644 --- a/lib/rules/widget-not-inline-matches.js +++ b/lib/rules/widget-not-inline-matches.js @@ -14,7 +14,8 @@ const matchesFns = [ (node, vNode) => isFocusable(vNode), // Skip nested widgets with tabindex=-1 (node, vNode) => isInTabOrder(vNode) || !hasWidgetAncestorInTabOrder(vNode), - node => !isInTextBlock(node, { noLengthCompare: true }) + node => + !isInTextBlock(node, { noLengthCompare: true, includeInlineBlock: true }) ]; function isWidgetType(vNode) { diff --git a/test/commons/dom/is-in-text-block.js b/test/commons/dom/is-in-text-block.js index 936669371..4693ad386 100644 --- a/test/commons/dom/is-in-text-block.js +++ b/test/commons/dom/is-in-text-block.js @@ -1,138 +1,132 @@ -describe('dom.isInTextBlock', function () { - 'use strict'; +describe('dom.isInTextBlock', () => { + const fixture = document.getElementById('fixture'); + const { shadowSupport, fixtureSetup, queryFixture } = axe.testUtils; + const isInTextBlock = axe.commons.dom.isInTextBlock; - var fixture = document.getElementById('fixture'); - var shadowSupport = axe.testUtils.shadowSupport; - var fixtureSetup = axe.testUtils.fixtureSetup; - - afterEach(function () { - fixture.innerHTML = ''; - }); - - it('returns true if the element is a node in a block of text', function () { + it('returns true if the element is a node in a block of text', () => { fixtureSetup( '

Some paragraph with text ' + ' link' + '

' ); - var link = document.getElementById('link'); - assert.isTrue(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isTrue(isInTextBlock(link)); }); - it('returns false if the element is a block', function () { + it('returns false if the element is a block', () => { fixtureSetup( '

Some paragraph with text ' + ' link' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('returns false if the element has the only text in the block', function () { + it('returns false if the element has the only text in the block', () => { fixtureSetup('

link

'); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('returns false if there is more text in link(s) than in the rest of the block', function () { + it('returns false if there is more text in link(s) than in the rest of the block', () => { fixtureSetup( '

short text:' + ' on a link with a very long text' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('return false if there are links along side other links', function () { + it('return false if there are links along side other links', () => { fixtureSetup( '

' + ' link' + ' other link' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('ignores hidden content', function () { + it('ignores hidden content', () => { fixtureSetup( '

' + ' link' + ' some hidden text' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('ignores floated content', function () { + it('ignores floated content', () => { fixtureSetup( '

' + ' A floating text in the area' + ' link' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('ignores positioned content', function () { + it('ignores positioned content', () => { fixtureSetup( '

' + ' Some absolute potitioned text' + ' link' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('ignores none-text content', function () { + it('ignores none-text content', () => { fixtureSetup( '

' + ' Some graphical component' + ' link' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('ignore text in the block coming before a br', function () { + it('ignore text in the block coming before a br', () => { fixtureSetup( '

Some paragraph with text
' + ' link' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('ignore text in the block coming after a br', function () { + it('ignore text in the block coming after a br', () => { fixtureSetup( '

' + ' link
' + ' Some paragraph with text ' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('ignore text in the block coming before and after a br', function () { + it('ignore text in the block coming before and after a br', () => { fixtureSetup( '

Some paragraph with text
' + ' link
' + ' Some paragraph with text ' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('ignores text inside inline widgets and components', function () { + it('ignores text inside inline widgets and components', () => { fixtureSetup( '

' + ' link' + @@ -143,81 +137,188 @@ describe('dom.isInTextBlock', function () { ' ' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('treats hr elements the same as br elements', function () { + it('treats hr elements the same as br elements', () => { fixtureSetup( '
Some paragraph with text
' + ' link
' + ' Some paragraph with text ' + '
' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - it('ignore comments', function () { + it('ignore comments', () => { fixtureSetup( '

' + ' link' + '

' ); - var link = document.getElementById('link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link)); }); - (shadowSupport.v1 ? it : xit)('can reach outside a shadow tree', function () { - var div = document.createElement('div'); + (shadowSupport.v1 ? it : xit)('can reach outside a shadow tree', () => { + const div = document.createElement('div'); div.innerHTML = 'Some paragraph with text '; - var shadow = div.querySelector('span').attachShadow({ mode: 'open' }); + const shadow = div.querySelector('span').attachShadow({ mode: 'open' }); shadow.innerHTML = 'link'; fixtureSetup(div); - var link = shadow.querySelector('#link'); - assert.isTrue(axe.commons.dom.isInTextBlock(link)); + const link = shadow.querySelector('#link'); + assert.isTrue(isInTextBlock(link)); }); - (shadowSupport.v1 ? it : xit)('can reach into a shadow tree', function () { - var div = document.createElement('div'); + (shadowSupport.v1 ? it : xit)('can reach into a shadow tree', () => { + const div = document.createElement('div'); div.innerHTML = 'link'; - var shadow = div.attachShadow({ mode: 'open' }); + const shadow = div.attachShadow({ mode: 'open' }); shadow.innerHTML = '

Some paragraph with text

'; fixtureSetup(div); - var link = fixture.querySelector('#link'); - assert.isTrue(axe.commons.dom.isInTextBlock(link)); + const link = fixture.querySelector('#link'); + assert.isTrue(isInTextBlock(link)); }); - (shadowSupport.v1 ? it : xit)( - 'treats shadow DOM slots as siblings', - function () { - var div = document.createElement('div'); - div.innerHTML = '
'; - var shadow = div.attachShadow({ mode: 'open' }); - shadow.innerHTML = - '

Some paragraph with text ' + - ' link

'; - fixtureSetup(div); + (shadowSupport.v1 ? it : xit)('treats shadow DOM slots as siblings', () => { + const div = document.createElement('div'); + div.innerHTML = '
'; + const shadow = div.attachShadow({ mode: 'open' }); + shadow.innerHTML = + '

Some paragraph with text ' + + ' link

'; + fixtureSetup(div); + + const link = shadow.querySelector('#link'); + assert.isFalse(isInTextBlock(link)); + }); + + describe('inline-block element', () => { + it('returns false if element has widget parent', () => { + const target = queryFixture(` +
+ +
+ `); + assert.isFalse(isInTextBlock(target)); + }); + + it('returns false if element has focusable parent', () => { + const target = queryFixture(` +
+ +
+ `); + assert.isFalse(isInTextBlock(target)); + }); + + it('returns false if element has text sibling', () => { + const target = queryFixture(` +
+ Hello world + +
+ `); + assert.isFalse(isInTextBlock(target)); + }); + + it('returns false if element has inline element sibling', () => { + const target = queryFixture(` +
+ Hello world + +
+ `); + assert.isFalse(isInTextBlock(target)); + }); + + it('returns false if element has inline-block element sibling', () => { + const target = queryFixture(` +
+
Hello world
+ +
+ `); + assert.isFalse(isInTextBlock(target)); + }); + + it('returns false if element has widget element sibling', () => { + const target = queryFixture(` +
+
Hello world
+ +
+ `); + assert.isFalse(isInTextBlock(target)); + }); + + it('ignores br elements', () => { + const target = queryFixture(` +
+ Hello World +
+ +
+ `); + assert.isFalse(isInTextBlock(target)); + }); + + it('ignores hr elements', () => { + const target = queryFixture(` +
+ Hello World +
+ +
+ `); + assert.isFalse(isInTextBlock(target)); + }); + + it('looks at all siblings', () => { + const target = queryFixture(` +
+
+ +
+
Hello world
+
+ `); + assert.isFalse(isInTextBlock(target)); + }); - var link = shadow.querySelector('#link'); - assert.isFalse(axe.commons.dom.isInTextBlock(link)); - } - ); + it('works for inline-grid', () => { + const target = queryFixture(` +
+
Hello world
+ +
+ `); + assert.isFalse(isInTextBlock(target)); + }); - describe('options.noLengthCompare', function () { - it('returns true if there is any text outside the link', function () { + it('works for inline-flex', () => { + const target = queryFixture(` +
+
Hello world
+ +
+ `); + assert.isFalse(isInTextBlock(target)); + }); + }); + + describe('options.noLengthCompare', () => { + it('returns true if there is any text outside the link', () => { fixtureSetup('

amy link text is longer

'); - var link = document.getElementById('link'); - assert.isTrue( - axe.commons.dom.isInTextBlock(link, { - noLengthCompare: true - }) - ); + const link = document.getElementById('link'); + assert.isTrue(isInTextBlock(link, { noLengthCompare: true })); }); - it('returns false if the non-widget text is only whitespace', function () { + it('returns false if the non-widget text is only whitespace', () => { fixtureSetup( '

' + ' link 1\t\n\r' + @@ -226,12 +327,74 @@ describe('dom.isInTextBlock', function () { ' link 4' + '

' ); - var link = document.getElementById('link'); - assert.isFalse( - axe.commons.dom.isInTextBlock(link, { - noLengthCompare: true - }) - ); + const link = document.getElementById('link'); + assert.isFalse(isInTextBlock(link, { noLengthCompare: true })); + }); + }); + + describe('with options.includeInlineBlock: true', () => { + it('returns true if inline-block element has text sibling', () => { + const target = queryFixture(` +
+ Hello world + +
+ `); + assert.isTrue(isInTextBlock(target, { includeInlineBlock: true })); + }); + + it('returns true if inline-block element has inline element sibling', () => { + const target = queryFixture(` +
+ Hello world + +
+ `); + assert.isTrue(isInTextBlock(target, { includeInlineBlock: true })); + }); + + it('returns true if inline-block element has text sibling after it', () => { + const target = queryFixture(` +
+ hello world +
+ `); + assert.isTrue(isInTextBlock(target, { includeInlineBlock: true })); + }); + + it('returns true if inline-block element has both inline text and a widget sibling', () => { + const target = queryFixture(` +
+ + Hello world, goodbye mars + +
+ `); + assert.isTrue(isInTextBlock(target, { includeInlineBlock: true })); + }); + + it('returns false the inline text sibling is on a different line', () => { + const target = queryFixture(` +
+ Hello +
+ +
+ world +
+ `); + assert.isFalse(isInTextBlock(target, { includeInlineBlock: true })); + }); + + it('returns true if inline-block element has a sibling on the same line', () => { + const target = queryFixture(` +
+ Hello +
+ world +
+ `); + assert.isFalse(isInTextBlock(target, { includeInlineBlock: true })); }); }); }); diff --git a/test/integration/rules/target-size/target-size.html b/test/integration/rules/target-size/target-size.html index c57bd9e7b..8f6ff287f 100644 --- a/test/integration/rules/target-size/target-size.html +++ b/test/integration/rules/target-size/target-size.html @@ -68,6 +68,30 @@
Timer
+ +
+

+ This is a in a + sentence. +

+ +
+

- x + + x

    diff --git a/test/integration/rules/target-size/target-size.json b/test/integration/rules/target-size/target-size.json index 5f8d2e148..570d08350 100644 --- a/test/integration/rules/target-size/target-size.json +++ b/test/integration/rules/target-size/target-size.json @@ -36,6 +36,7 @@ ["#pass22"], ["#pass23"], ["#pass24"], + ["#pass25"], ["#pass-adjacent"], ["#pass-fixed"] ], From 66c26aaa9e9a76af34274ab86267cd9c2005d418 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Mon, 30 Mar 2026 11:44:42 -0600 Subject: [PATCH 20/32] chore(release): 4.11.2 --- CHANGELOG.md | 13 +++++++++++++ bower.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- sri-history.json | 4 ++++ 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f9b2b8f0..33d846e41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [4.11.2](https://github.com/dequelabs/axe-core/compare/v4.11.1...v4.11.2) (2026-03-30) + +### Bug Fixes + +- **aria-valid-attr-value:** handle multiple aria-errormessage IDs ([#4973](https://github.com/dequelabs/axe-core/issues/4973)) ([9322148](https://github.com/dequelabs/axe-core/commit/9322148b69924d6ae2d2dd46e6109bc2fc53abd3)) +- **aria:** prevent getOwnedVirtual from returning duplicate nodes ([#4987](https://github.com/dequelabs/axe-core/issues/4987)) ([99d1e77](https://github.com/dequelabs/axe-core/commit/99d1e77f351db586c79020372efc59608e604a1c)), closes [#4840](https://github.com/dequelabs/axe-core/issues/4840) +- **DqElement:** avoid calling constructors with cloneNode ([#5013](https://github.com/dequelabs/axe-core/issues/5013)) ([88bc57f](https://github.com/dequelabs/axe-core/commit/88bc57fd3de12cd69d365b3f385ce9a2e30b7bd5)) +- **existing-rule:** aria-busy now shows an error message for a use with unallowed children ([#5017](https://github.com/dequelabs/axe-core/issues/5017)) ([dded75a](https://github.com/dequelabs/axe-core/commit/dded75a9acc9a2350926f46f04e0f1de522f43d6)) +- **scrollable-region-focusable:** clarify the issue is in safari ([#4995](https://github.com/dequelabs/axe-core/issues/4995)) ([2567afd](https://github.com/dequelabs/axe-core/commit/2567afd5c32398c6a488240b066bb0d335f6dc6a)), closes [WebKit#190870](https://github.com/dequelabs/WebKit/issues/190870) [WebKit#277290](https://github.com/dequelabs/WebKit/issues/277290) +- **scrollable-region-focusable:** do not fail scroll areas when all content is visible without scrolling ([#4993](https://github.com/dequelabs/axe-core/issues/4993)) ([240f8b5](https://github.com/dequelabs/axe-core/commit/240f8b53ad168521a63b54d0053b96ce430c7184)) +- **target-size:** determine offset using clientRects if target is display:inline ([#5012](https://github.com/dequelabs/axe-core/issues/5012)) ([69d81c1](https://github.com/dequelabs/axe-core/commit/69d81c1cbb6a61a272884516c7983dcd17d28a42)) +- **target-size:** ignore widgets that are inline with other inline elements ([#5000](https://github.com/dequelabs/axe-core/issues/5000)) ([cf8a3c0](https://github.com/dequelabs/axe-core/commit/cf8a3c039b121c0c64a1eb8805c586659b69f3c1)) + ### [4.11.1](https://github.com/dequelabs/axe-core/compare/v4.11.0...v4.11.1) (2026-01-06) ### Bug Fixes diff --git a/bower.json b/bower.json index d1d2ba54d..8469cdf9a 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "axe-core", - "version": "4.11.1", + "version": "4.11.2", "deprecated": true, "contributors": [ { diff --git a/package-lock.json b/package-lock.json index a5bea7637..fcdf925de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "axe-core", - "version": "4.11.1", + "version": "4.11.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "axe-core", - "version": "4.11.1", + "version": "4.11.2", "license": "MPL-2.0", "devDependencies": { "@axe-core/webdriverjs": "^4.10.2", diff --git a/package.json b/package.json index 655745309..239cdd068 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "axe-core", "description": "Accessibility engine for automated Web UI testing", - "version": "4.11.1", + "version": "4.11.2", "license": "MPL-2.0", "engines": { "node": ">=4" diff --git a/sri-history.json b/sri-history.json index 063400e52..ad8030df6 100644 --- a/sri-history.json +++ b/sri-history.json @@ -402,5 +402,9 @@ "4.11.1": { "axe.js": "sha256-fJzJf10MFoA2ixvyHh+fGvPuVq6JXm+IdhMVfaKAnYY=", "axe.min.js": "sha256-fb+r38YGKTbXnIc927X4EaEhn8o5KL2Myd2B8eZfRyA=" + }, + "4.11.2": { + "axe.js": "sha256-l0az3GGxixpCq0IHsMxs3F4nvNGl/89Ypf8icbh6Xfk=", + "axe.min.js": "sha256-dacAeIgHzdkplnXlC66fYnqfnzaOkpb+pxf3Ejreyxo=" } } From 7e06043609344ee33604d8aba10309a1e60b077e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:47:45 -0400 Subject: [PATCH 21/32] chore: bump actions/download-artifact from 7.0.0 to 8.0.1 (#5056) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7.0.0 to 8.0.1.
    Release notes

    Sourced from actions/download-artifact's releases.

    v8.0.1

    What's Changed

    Full Changelog: https://github.com/actions/download-artifact/compare/v8...v8.0.1

    v8.0.0

    v8 - What's new

    [!IMPORTANT] actions/download-artifact@v8 has been migrated to an ESM module. This should be transparent to the caller but forks might need to make significant changes.

    [!IMPORTANT] Hash mismatches will now error by default. Users can override this behavior with a setting change (see below).

    Direct downloads

    To support direct uploads in actions/upload-artifact, the action will no longer attempt to unzip all downloaded files. Instead, the action checks the Content-Type header ahead of unzipping and skips non-zipped files. Callers wishing to download a zipped file as-is can also set the new skip-decompress parameter to true.

    Enforced checks (breaking)

    A previous release introduced digest checks on the download. If a download hash didn't match the expected hash from the server, the action would log a warning. Callers can now configure the behavior on mismatch with the digest-mismatch parameter. To be secure by default, we are now defaulting the behavior to error which will fail the workflow run.

    ESM

    To support new versions of the @actions/* packages, we've upgraded the package to ESM.

    What's Changed

    Full Changelog: https://github.com/actions/download-artifact/compare/v7...v8.0.0

    Commits
    • 3e5f45b Add regression tests for CJK characters (#471)
    • e6d03f6 Add a regression test for artifact name + content-type mismatches (#472)
    • 70fc10c Merge pull request #461 from actions/danwkennedy/digest-mismatch-behavior
    • f258da9 Add change docs
    • ccc058e Fix linting issues
    • bd7976b Add a setting to specify what to do on hash mismatch and default it to error
    • ac21fcf Merge pull request #460 from actions/danwkennedy/download-no-unzip
    • 15999bf Add note about package bumps
    • 974686e Bump the version to v8 and add release notes
    • fbe48b1 Update test names to make it clearer what they do
    • Additional commits viewable in compare view

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/download-artifact&package-manager=github_actions&previous-version=7.0.0&new-version=8.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) 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-automerge-start) [//]: # (dependabot-automerge-end) ---
    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 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)
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7988fcc0c..9c9ec6cf0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -136,7 +136,7 @@ jobs: - *install-deps - &restore-axe-build name: Restore axe build - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: axe-core - name: Run ACT Tests From 0463a3f0e5c20a8edd54d9479e3df74c0111797c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:48:28 -0400 Subject: [PATCH 22/32] chore: bump actions/upload-artifact from 6.0.0 to 7.0.0 (#5054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6.0.0 to 7.0.0.
    Release notes

    Sourced from actions/upload-artifact's releases.

    v7.0.0

    v7 What's new

    Direct Uploads

    Adds support for uploading single files directly (unzipped). Callers can set the new archive parameter to false to skip zipping the file during upload. Right now, we only support single files. The action will fail if the glob passed resolves to multiple files. The name parameter is also ignored with this setting. Instead, the name of the artifact will be the name of the uploaded file.

    ESM

    To support new versions of the @actions/* packages, we've upgraded the package to ESM.

    What's Changed

    New Contributors

    Full Changelog: https://github.com/actions/upload-artifact/compare/v6...v7.0.0

    Commits

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=6.0.0&new-version=7.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) 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-automerge-start) [//]: # (dependabot-automerge-end) ---
    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 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)
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9c9ec6cf0..4e484e9a7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -64,7 +64,7 @@ jobs: run: | npm run prepare npm run build - - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: axe-core path: axe.js From baa580b9d0589189c50230de89c6ed77286b9753 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:49:15 -0400 Subject: [PATCH 23/32] chore: bump the npm-low-risk group with 8 updates (#5053) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the npm-low-risk group with 8 updates: | Package | From | To | | --- | --- | --- | | [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) | `7.29.0` | `7.29.2` | | [@babel/runtime-corejs3](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime-corejs3) | `7.29.0` | `7.29.2` | | [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) | `3.48.0` | `3.49.0` | | [globals](https://github.com/sindresorhus/globals) | `17.3.0` | `17.4.0` | | [lint-staged](https://github.com/lint-staged/lint-staged) | `16.2.7` | `16.4.0` | | [serve-handler](https://github.com/vercel/serve-handler) | `6.1.6` | `6.1.7` | | [sinon](https://github.com/sinonjs/sinon) | `21.0.1` | `21.0.3` | | [start-server-and-test](https://github.com/bahmutov/start-server-and-test) | `2.1.3` | `2.1.5` | Updates `@babel/preset-env` from 7.29.0 to 7.29.2
    Release notes

    Sourced from @​babel/preset-env's releases.

    v7.29.2 (2026-03-16)

    :eyeglasses: Spec Compliance

    • babel-parser

    :bug: Bug Fix

    • babel-helpers, babel-plugin-transform-async-generator-functions, babel-preset-env, babel-runtime-corejs3
    • babel-preset-env
      • #17789 [7.x backport] preset-env include/exclude should accept bugfix plugins (@​JLHwung)

    :house: Internal

    Committers: 2

    v7.29.1 (2026-02-04)

    :bug: Bug Fix

    Committers: 2

    Commits

    Updates `@babel/runtime-corejs3` from 7.29.0 to 7.29.2
    Release notes

    Sourced from @​babel/runtime-corejs3's releases.

    v7.29.2 (2026-03-16)

    :eyeglasses: Spec Compliance

    • babel-parser

    :bug: Bug Fix

    • babel-helpers, babel-plugin-transform-async-generator-functions, babel-preset-env, babel-runtime-corejs3
    • babel-preset-env
      • #17789 [7.x backport] preset-env include/exclude should accept bugfix plugins (@​JLHwung)

    :house: Internal

    Committers: 2

    v7.29.1 (2026-02-04)

    :bug: Bug Fix

    Committers: 2

    Commits

    Updates `core-js` from 3.48.0 to 3.49.0
    Changelog

    Sourced from core-js's changelog.

    3.49.0 - 2026.03.16

    • Changes v3.48.0...v3.49.0 (373 commits)
    • Iterator.range updated following the actual spec version
      • Throw a RangeError on NaN start / end / step
      • Allow null as optionOrStep
    • Improved accuracy of Math.{ asinh, atanh } polyfills with big and small values
    • Improved accuracy of Number.prototype.toExponential polyfills with big and small values
    • Improved performance of atob, btoa, Uint8Array.fromHex, Uint8Array.prototype.setFromHex, and Uint8Array.prototype.toHex, #1503, #1464, #1510, thanks @​johnzhou721
    • Minor performance optimization polyfills of methods from Map upsert proposal
    • Polyfills of methods from Map upsert proposal from the pure version made generic to make it work with polyfilled and native collections
    • Wrap Symbol.for in Symbol.prototype.description polyfill for correct handling of empty string descriptions
    • Fixed a modern Safari bug in Array.prototype.includes with sparse arrays and fromIndex
    • Fixed one more case (Iterator.prototype.take) of a V8 ~ Chromium < 126 bug
    • Forced replacement of Iterator.{ concat, zip, zipKeyed } in the pure version for ensuring proper wrapped Iterator instances as the result
    • Fixed proxying .return() on exhausted iterator from some methods of iterator helpers polyfill to the underlying iterator
    • Fixed double .return() calling in case of throwing error in this method in the internal iterate helper that affected some polyfills
    • Fixed closing iterator on IteratorValue errors in the internal iterate helper that affected some polyfills
    • Fixed iterator closing in Array.from polyfill on failure to create array property
    • Fixed order of arguments validation in Array.fromAsync polyfill
    • Fixed a lack of counter validation on MAX_SAFE_INTEGER in Array.fromAsync polyfill
    • Fixed order of arguments validation in Array.prototype.flat polyfill
    • Fixed handling strings as iterables in Iterator.{ zip, zipKeyed } polyfills
    • Fixed some cases of iterators closing in Iterator.{ zip, zipKeyed } polyfills
    • Fixed validation of iterators .next() results an objects in Iterator.{ zip, zipKeyed } polyfills
    • Fixed a lack of early error in Iterator.concat polyfill on primitive as an iterator
    • Fixed buffer mutation exposure in Iterator.prototype.windows polyfill
    • Fixed iterator closing in Set.prototype.{ isDisjointFrom, isSupersetOf } polyfill
    • Fixed (updated following the final spec) one more case Set.prototype.difference polyfill with updating this
    • Fixed DataView.prototype.setFloat16 polyfill in (0, 1) range
    • Fixed order of arguments validation in String.prototype.{ padStart, padEnd } polyfills
    • Fixed order of arguments validation in String.prototype.{ startsWith, endsWith } polyfills
    • Fixed some cases of Infinity handling in String.prototype.substr polyfill
    • Fixed String.prototype.repeat polyfill with a counter exceeding 2 ** 32
    • Fixed some cases of chars case in escape polyfill
    • Fixed named backreferences in RegExp NCG polyfill
    • Fixed some cases of RegExp NCG polyfill in combination with other types of groups
    • Fixed some cases of RegExp NCG polyfill in combination with dotAll
    • Fixed String.prototype.replace with sticky polyfill, #810, #1514
    • Fixed RegExp sticky polyfill with alternation
    • Fixed handling of some line terminators in case of multiline + sticky mode in RegExp polyfill
    • Fixed .input slicing on result object with RegExp sticky mode polyfill
    • Fixed handling of empty groups with global and unicode modes in polyfills
    • Fixed URLSearchParam.prototype.delete polyfill with duplicate key-value pairs
    • Fixed possible removal of unnecessary entries in URLSearchParam.prototype.delete polyfill with second argument
    • Fixed an error in some cases of non-special URLs without a path in the URL polyfill
    • Fixed some percent encode cases / character sets in the URL polyfill
    • Fixed parsing of non-IPv4 hosts ends in a number in the URL polyfill
    • Fixed some cases of '' and null host handling in the URL polyfill
    • Fixed host parsing with hostname = host:port in the URL polyfill
    • Fixed host inheritance in some cases of file scheme in the URL polyfill

    ... (truncated)

    Commits
    • 80adfc4 v3.49.0
    • 0ad3e00 fix a modern Safari bug in Array.prototype.includes with sparse arrays and ...
    • 853bfa4 update some links
    • b4d723f fix a lack of counter validation on MAX_SAFE_INTEGER in Array.fromAsync p...
    • e276676 fix parsing of non-IPv4 hosts ends in a number in the URL polyfill
    • dd1cfba fix order of arguments validation in String.prototype.{ padStart, padEnd } ...
    • b952c5f add an extra protection to configurator
    • e490caf Fix for #810 (#1514)
    • 10b4e86 drop an unneeded comment
    • 28cf2e9 feat: Improve performance of Uint8Array Hex functions (#1510)
    • Additional commits viewable in compare view

    Updates `globals` from 17.3.0 to 17.4.0
    Release notes

    Sourced from globals's releases.

    v17.4.0

    • Update globals (2026-03-01) (#338) d43a051

    https://github.com/sindresorhus/globals/compare/v17.3.0...v17.4.0

    Commits

    Updates `lint-staged` from 16.2.7 to 16.4.0
    Release notes

    Sourced from lint-staged's releases.

    v16.4.0

    Minor Changes

    v16.3.4

    Patch Changes

    v16.3.3

    Patch Changes

    • #1740 0109e8d Thanks @​iiroj! - Make sure Git's warning about CRLF line-endings doesn't interfere with creating initial backup stash.

    v16.3.2

    Patch Changes

    • #1735 2adaf6c Thanks @​iiroj! - Hide the extra cmd window on Windows by spawning tasks without the detached option.

    v16.3.1

    Patch Changes

    • #1729 cd5d762 Thanks @​iiroj! - Remove nano-spawn as a dependency from package.json as it was replaced with tinyexec and is no longer used.

    v16.3.0

    Minor Changes

    • #1698 feda37a Thanks @​iiroj! - Run external processes with tinyexec instead of nano-spawn. nano-spawn replaced execa in lint-staged version 16 to limit the amount of npm dependencies required, but caused some unknown issues related to spawning tasks. Let's hope tinyexec improves the situation.

    • #1699 1346d16 Thanks @​iiroj! - Remove pidtree as a dependency. When a task fails, its sub-processes are killed more efficiently via the process group on Unix systems, and the taskkill command on Windows.

    Patch Changes

    • #1726 87467aa Thanks @​iiroj! - Incorrect brace expansions like *.{js} (nothing to expand) are detected exhaustively, instead of just a single pass.
    Changelog

    Sourced from lint-staged's changelog.

    16.4.0

    Minor Changes

    16.3.4

    Patch Changes

    16.3.3

    Patch Changes

    • #1740 0109e8d Thanks @​iiroj! - Make sure Git's warning about CRLF line-endings doesn't interfere with creating initial backup stash.

    16.3.2

    Patch Changes

    • #1735 2adaf6c Thanks @​iiroj! - Hide the extra cmd window on Windows by spawning tasks without the detached option.

    16.3.1

    Patch Changes

    • #1729 cd5d762 Thanks @​iiroj! - Remove nano-spawn as a dependency from package.json as it was replaced with tinyexec and is no longer used.

    16.3.0

    Minor Changes

    • #1698 feda37a Thanks @​iiroj! - Run external processes with tinyexec instead of nano-spawn. nano-spawn replaced execa in lint-staged version 16 to limit the amount of npm dependencies required, but caused some unknown issues related to spawning tasks. Let's hope tinyexec improves the situation.

    • #1699 1346d16 Thanks @​iiroj! - Remove pidtree as a dependency. When a task fails, its sub-processes are killed more efficiently via the process group on Unix systems, and the taskkill command on Windows.

    Patch Changes

    • #1726 87467aa Thanks @​iiroj! - Incorrect brace expansions like *.{js} (nothing to expand) are detected exhaustively, instead of just a single pass.
    Commits
    • 445f9dd chore(changeset): release
    • d91be60 docs: update readme to use picomatch
    • b392a9f refactor: extract matchFiles and add unit tests
    • 687fc90 refactor: replace micromatch with picomatch
    • 26dadf9 chore(changeset): release
    • 9d6e827 build(deps): update dependencies
    • 8aea986 chore(changeset): release
    • 0109e8d fix: strip Git CRLF warning from output
    • dfd6a7a chore(changeset): release
    • 2adaf6c fix(Windows): do not spawn tasks as detached since it opens a cmd window on ...
    • Additional commits viewable in compare view

    Updates `serve-handler` from 6.1.6 to 6.1.7
    Release notes

    Sourced from serve-handler's releases.

    6.1.7

    Patches

    • Fix: update minimatch to 3.1.5 to resolve security vulnerabilities: #228

    Credits

    Huge thanks to @​ParakhJaggi for helping!

    Commits

    Updates `sinon` from 21.0.1 to 21.0.3
    Changelog

    Sourced from sinon's changelog.

    21.0.3

    • 0494251b fix(#2678): upgrade samsam to fix buffer comparisons (Carl-Erik Kopseng)

    Released by Carl-Erik Kopseng on 2026-03-16.

    21.0.2

    • 024321c4 fix: skip Node specific tests in browser env (Carl-Erik Kopseng)
    • b836fccb fix: js-yaml breaking change from v3 to v4 (Carl-Erik Kopseng)
    • ebf0c431 docs: add how-to article for stubbing ES module imports (#1832) (#2676) (Eduard Barrera)
      • docs: add how-to article for stubbing ES module imports with esm package

      Adds a comprehensive How-To guide that addresses issue #1832, documenting how to configure Node.js to allow Sinon stubs to work with ES modules.

      • Explains why ES module namespace bindings are immutable by spec
      • Shows how to use the 'esm' npm package with mutableNamespace: true
      • Provides a complete working example with project layout, package.json, loader file, source modules, and a full test suite
      • Documents limitations (destructured imports, non-standard behavior)
      • Replaces the TODO comment in link-seams-commonjs.md with a cross-reference

      Closes #1832 Co-authored-by: Eduard Barrera eduardbar@users.noreply.github.com Co-authored-by: Carl-Erik Kopseng carlerik@gmail.com

    • ebcd506c Fix spies not being reset properly (#2673) (simon-id)
    • 3beab2ba Make doc tests pass with new jQuery (Carl-Erik Kopseng)
    • 766715c6 build: reduce transitive audit findings (Carl-Erik Kopseng)
    • 92aaf5c9 build: upgrade eslint config and replace dependency-check (Carl-Erik Kopseng)
    • c6aaa871 chore: ignore project worktrees (Carl-Erik Kopseng)
    • ef387e8e Upgrade most deps (Carl-Erik Kopseng)
    • 3cf4e77d docs: improve writing of documentation (#2675) (Eduardo de la Cruz Palacios)
    • 6349032f Check login status before publishing steps are performed (Carl-Erik Kopseng)

    Released by Carl-Erik Kopseng on 2026-03-04.

    Commits

    Updates `start-server-and-test` from 2.1.3 to 2.1.5
    Release notes

    Sourced from start-server-and-test's releases.

    v2.1.5

    2.1.5 (2026-02-24)

    Bug Fixes

    • formatting the message in the constructor of Error object (#395) (9d135de)

    v2.1.4

    2.1.4 (2026-02-24)

    Bug Fixes

    Commits
    Maintainer changes

    This version was pushed to npm by [GitHub Actions](https://www.npmjs.com/~GitHub Actions), a new releaser for start-server-and-test since your current version.


    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-automerge-start) [//]: # (dependabot-automerge-end) ---
    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 ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
    Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 421 ++++++++++++++++++++++++---------------------- 1 file changed, 219 insertions(+), 202 deletions(-) diff --git a/package-lock.json b/package-lock.json index fcdf925de..2d03b3175 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1543,9 +1543,9 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", - "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.2.tgz", + "integrity": "sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw==", "dev": true, "dependencies": { "@babel/compat-data": "^7.29.0", @@ -1641,9 +1641,9 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.0.tgz", - "integrity": "sha512-TgUkdp71C9pIbBcHudc+gXZnihEDOjUAmXO1VO4HHGES7QLZcShR0stfKIxLSNIYx2fqhmJChOjm/wkF8wv4gA==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.2.tgz", + "integrity": "sha512-Lc94FOD5+0aXhdb0Tdg3RUtqT6yWbI/BbFWvlaSJ3gAb9Ks+99nHRDKADVqC37er4eCB0fHyWT+y+K3QOvJKbw==", "dev": true, "dependencies": { "core-js-pure": "^3.48.0" @@ -2046,9 +2046,9 @@ "dev": true }, "node_modules/@hapi/tlds": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.4.tgz", - "integrity": "sha512-Fq+20dxsxLaUn5jSSWrdtSRcIUba2JquuorF9UW1wIJS5cSUwxIsO2GIhaWynPRflvxSzFN+gxKte2HEW1OuoA==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.6.tgz", + "integrity": "sha512-xdi7A/4NZokvV0ewovme3aUO5kQhW9pQ2YD1hRqZGhhSi5rBv4usHYidVocXSi9eihYsznZxLtAiEYYUL6VBGw==", "dev": true, "engines": { "node": ">=14.0.0" @@ -2426,18 +2426,18 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.0.tgz", - "integrity": "sha512-cqfapCxwTGsrR80FEgOoPsTonoefMBY7dnUEbQ+GRcved0jvkJLzvX6F4WtN+HBqbPX/SiFsIRUp+IrCW/2I2w==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.2.1.tgz", + "integrity": "sha512-QdfpQFIwYrTK8lFsII4bJ1AO1ZLbw7B+oxfP+/qSsiTrVerFp7aY2O+d2GNGrTxP58ezEbjbf7mTTLMsd7M7XQ==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "node_modules/@sinonjs/samsam": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", - "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-9.0.3.tgz", + "integrity": "sha512-ZgYY7Dc2RW+OUdnZ1DEHg00lhRt+9BjymPKHog4PRFzr1U3MbK57+djmscWyKxzO1qfunHqs4N45WWyKIFKpiQ==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.1", @@ -2460,9 +2460,9 @@ "dev": true }, "node_modules/@standard-schema/spec": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true }, "node_modules/@testim/chrome-version": { @@ -2794,14 +2794,23 @@ } }, "node_modules/axios": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", - "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz", + "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", "dev": true, "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/axios/node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "dev": true, + "engines": { + "node": ">=10" } }, "node_modules/babel-plugin-polyfill-corejs2": { @@ -3688,9 +3697,9 @@ } }, "node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "dev": true, "engines": { "node": ">=20" @@ -4247,9 +4256,9 @@ } }, "node_modules/core-js": { - "version": "3.48.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", - "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", + "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", "dev": true, "hasInstallScript": true, "funding": { @@ -5852,9 +5861,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "dev": true, "funding": [ { @@ -5921,9 +5930,9 @@ } }, "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, "dependencies": { "asynckit": "^0.4.0", @@ -6389,9 +6398,9 @@ } }, "node_modules/globals": { - "version": "17.3.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.3.0.tgz", - "integrity": "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==", + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz", + "integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==", "dev": true, "engines": { "node": ">=18" @@ -7903,9 +7912,9 @@ } }, "node_modules/joi": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-18.0.2.tgz", - "integrity": "sha512-RuCOQMIt78LWnktPoeBL0GErkNaJPTBGcYuyaBvUOQSpcpcLfWrHPPihYdOGbV5pam9VTWbeoF7TsGiHugcjGA==", + "version": "18.1.2", + "resolved": "https://registry.npmjs.org/joi/-/joi-18.1.2.tgz", + "integrity": "sha512-rF5MAmps5esSlhCA+N1b6IYHDw9j/btzGaqfgie522jS02Ju/HXBxamlXVlKEHAxoMKQL77HWI8jlqWsFuekZA==", "dev": true, "dependencies": { "@hapi/address": "^5.1.1", @@ -7914,7 +7923,7 @@ "@hapi/pinpoint": "^2.0.1", "@hapi/tlds": "^1.1.1", "@hapi/topo": "^6.0.2", - "@standard-schema/spec": "^1.0.0" + "@standard-schema/spec": "^1.1.0" }, "engines": { "node": ">= 20" @@ -8520,18 +8529,17 @@ } }, "node_modules/lint-staged": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", - "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.4.0.tgz", + "integrity": "sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==", "dev": true, "dependencies": { - "commander": "^14.0.2", + "commander": "^14.0.3", "listr2": "^9.0.5", - "micromatch": "^4.0.8", - "nano-spawn": "^2.0.0", - "pidtree": "^0.6.0", + "picomatch": "^4.0.3", "string-argv": "^0.3.2", - "yaml": "^2.8.1" + "tinyexec": "^1.0.4", + "yaml": "^2.8.2" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -8543,6 +8551,18 @@ "url": "https://opencollective.com/lint-staged" } }, + "node_modules/lint-staged/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/listr2": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", @@ -8685,9 +8705,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true }, "node_modules/lodash.debounce": { @@ -9230,9 +9250,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -9495,18 +9515,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "node_modules/nano-spawn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", - "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", - "dev": true, - "engines": { - "node": ">=20.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -10510,18 +10518,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -11387,15 +11383,15 @@ } }, "node_modules/serve-handler": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", - "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.7.tgz", + "integrity": "sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==", "dev": true, "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", "mime-types": "2.1.18", - "minimatch": "3.1.2", + "minimatch": "3.1.5", "path-is-inside": "1.0.2", "path-to-regexp": "3.3.0", "range-parser": "1.2.0" @@ -11551,15 +11547,15 @@ "dev": true }, "node_modules/sinon": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.1.tgz", - "integrity": "sha512-Z0NVCW45W8Mg5oC/27/+fCqIHFnW8kpkFOq0j9XJIev4Ld0mKmERaZv5DMLAb9fGCevjKwaEeIQz5+MBXfZcDw==", + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.3.tgz", + "integrity": "sha512-0x8TQFr8EjADhSME01u1ZK31yv2+bd6Z5NrBCHVM+n4qL1wFqbxftmeyi3bwlr49FbbzRfrqSFOpyHCOh/YmYA==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^15.1.0", - "@sinonjs/samsam": "^8.0.3", - "diff": "^8.0.2", + "@sinonjs/fake-timers": "^15.1.1", + "@sinonjs/samsam": "^9.0.3", + "diff": "^8.0.3", "supports-color": "^7.2.0" }, "funding": { @@ -11568,9 +11564,9 @@ } }, "node_modules/sinon/node_modules/diff": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", - "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", "dev": true, "engines": { "node": ">=0.3.1" @@ -11947,9 +11943,9 @@ } }, "node_modules/start-server-and-test": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.1.3.tgz", - "integrity": "sha512-k4EcbNjeg0odaDkAMlIeDVDByqX9PIgL4tivgP2tES6Zd8o+4pTq/HgbWCyA3VHIoZopB+wGnNPKYGGSByNriQ==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.1.5.tgz", + "integrity": "sha512-A/SbXpgXE25ScSkpLLqvGvVZT0ykN6+AzS8tVqMBCTxbJy2Nwuen59opT+afalK5aS+AuQmZs0EsLwjnuDN+/g==", "dev": true, "dependencies": { "arg": "^5.0.2", @@ -11959,7 +11955,7 @@ "execa": "5.1.1", "lazy-ass": "1.6.0", "ps-tree": "1.2.0", - "wait-on": "9.0.3" + "wait-on": "9.0.4" }, "bin": { "server-test": "src/bin/start.js", @@ -12403,6 +12399,15 @@ "ms": "^2.1.1" } }, + "node_modules/tinyexec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", + "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", + "dev": true, + "engines": { + "node": ">=18" + } + }, "node_modules/tldts": { "version": "7.0.16", "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.16.tgz", @@ -12867,14 +12872,14 @@ } }, "node_modules/wait-on": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-9.0.3.tgz", - "integrity": "sha512-13zBnyYvFDW1rBvWiJ6Av3ymAaq8EDQuvxZnPIw3g04UqGi4TyoIJABmfJ6zrvKo9yeFQExNkOk7idQbDJcuKA==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-9.0.4.tgz", + "integrity": "sha512-k8qrgfwrPVJXTeFY8tl6BxVHiclK11u72DVKhpybHfUL/K6KM4bdyK9EhIVYGytB5MJe/3lq4Tf0hrjM+pvJZQ==", "dev": true, "dependencies": { - "axios": "^1.13.2", - "joi": "^18.0.1", - "lodash": "^4.17.21", + "axios": "^1.13.5", + "joi": "^18.0.2", + "lodash": "^4.17.23", "minimist": "^1.2.8", "rxjs": "^7.8.2" }, @@ -13197,15 +13202,18 @@ "dev": true }, "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "dev": true, "bin": { "yaml": "bin.mjs" }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { @@ -14291,9 +14299,9 @@ } }, "@babel/preset-env": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", - "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.2.tgz", + "integrity": "sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw==", "dev": true, "requires": { "@babel/compat-data": "^7.29.0", @@ -14380,9 +14388,9 @@ } }, "@babel/runtime-corejs3": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.0.tgz", - "integrity": "sha512-TgUkdp71C9pIbBcHudc+gXZnihEDOjUAmXO1VO4HHGES7QLZcShR0stfKIxLSNIYx2fqhmJChOjm/wkF8wv4gA==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.2.tgz", + "integrity": "sha512-Lc94FOD5+0aXhdb0Tdg3RUtqT6yWbI/BbFWvlaSJ3gAb9Ks+99nHRDKADVqC37er4eCB0fHyWT+y+K3QOvJKbw==", "dev": true, "requires": { "core-js-pure": "^3.48.0" @@ -14619,9 +14627,9 @@ "dev": true }, "@hapi/tlds": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.4.tgz", - "integrity": "sha512-Fq+20dxsxLaUn5jSSWrdtSRcIUba2JquuorF9UW1wIJS5cSUwxIsO2GIhaWynPRflvxSzFN+gxKte2HEW1OuoA==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.6.tgz", + "integrity": "sha512-xdi7A/4NZokvV0ewovme3aUO5kQhW9pQ2YD1hRqZGhhSi5rBv4usHYidVocXSi9eihYsznZxLtAiEYYUL6VBGw==", "dev": true }, "@hapi/topo": { @@ -14925,18 +14933,18 @@ } }, "@sinonjs/fake-timers": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.0.tgz", - "integrity": "sha512-cqfapCxwTGsrR80FEgOoPsTonoefMBY7dnUEbQ+GRcved0jvkJLzvX6F4WtN+HBqbPX/SiFsIRUp+IrCW/2I2w==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.2.1.tgz", + "integrity": "sha512-QdfpQFIwYrTK8lFsII4bJ1AO1ZLbw7B+oxfP+/qSsiTrVerFp7aY2O+d2GNGrTxP58ezEbjbf7mTTLMsd7M7XQ==", "dev": true, "requires": { "@sinonjs/commons": "^3.0.1" } }, "@sinonjs/samsam": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", - "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-9.0.3.tgz", + "integrity": "sha512-ZgYY7Dc2RW+OUdnZ1DEHg00lhRt+9BjymPKHog4PRFzr1U3MbK57+djmscWyKxzO1qfunHqs4N45WWyKIFKpiQ==", "dev": true, "requires": { "@sinonjs/commons": "^3.0.1", @@ -14958,9 +14966,9 @@ "dev": true }, "@standard-schema/spec": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true }, "@testim/chrome-version": { @@ -15232,14 +15240,22 @@ "dev": true }, "axios": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", - "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz", + "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", "dev": true, "requires": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + }, + "dependencies": { + "proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "dev": true + } } }, "babel-plugin-polyfill-corejs2": { @@ -15892,9 +15908,9 @@ } }, "commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "dev": true }, "compare-func": { @@ -16332,9 +16348,9 @@ "dev": true }, "core-js": { - "version": "3.48.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", - "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", + "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", "dev": true }, "core-js-compat": { @@ -17545,9 +17561,9 @@ "dev": true }, "follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "dev": true }, "for-in": { @@ -17584,9 +17600,9 @@ } }, "form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, "requires": { "asynckit": "^0.4.0", @@ -17933,9 +17949,9 @@ } }, "globals": { - "version": "17.3.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.3.0.tgz", - "integrity": "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==", + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz", + "integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==", "dev": true }, "globule": { @@ -19012,9 +19028,9 @@ } }, "joi": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-18.0.2.tgz", - "integrity": "sha512-RuCOQMIt78LWnktPoeBL0GErkNaJPTBGcYuyaBvUOQSpcpcLfWrHPPihYdOGbV5pam9VTWbeoF7TsGiHugcjGA==", + "version": "18.1.2", + "resolved": "https://registry.npmjs.org/joi/-/joi-18.1.2.tgz", + "integrity": "sha512-rF5MAmps5esSlhCA+N1b6IYHDw9j/btzGaqfgie522jS02Ju/HXBxamlXVlKEHAxoMKQL77HWI8jlqWsFuekZA==", "dev": true, "requires": { "@hapi/address": "^5.1.1", @@ -19023,7 +19039,7 @@ "@hapi/pinpoint": "^2.0.1", "@hapi/tlds": "^1.1.1", "@hapi/topo": "^6.0.2", - "@standard-schema/spec": "^1.0.0" + "@standard-schema/spec": "^1.1.0" } }, "jquery": { @@ -19516,18 +19532,25 @@ } }, "lint-staged": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", - "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.4.0.tgz", + "integrity": "sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==", "dev": true, "requires": { - "commander": "^14.0.2", + "commander": "^14.0.3", "listr2": "^9.0.5", - "micromatch": "^4.0.8", - "nano-spawn": "^2.0.0", - "pidtree": "^0.6.0", + "picomatch": "^4.0.3", "string-argv": "^0.3.2", - "yaml": "^2.8.1" + "tinyexec": "^1.0.4", + "yaml": "^2.8.2" + }, + "dependencies": { + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true + } } }, "listr2": { @@ -19631,9 +19654,9 @@ } }, "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true }, "lodash.debounce": { @@ -20017,9 +20040,9 @@ "dev": true }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -20206,12 +20229,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "nano-spawn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", - "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", - "dev": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -20981,12 +20998,6 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, - "pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true - }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -21648,15 +21659,15 @@ } }, "serve-handler": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", - "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.7.tgz", + "integrity": "sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==", "dev": true, "requires": { "bytes": "3.0.0", "content-disposition": "0.5.2", "mime-types": "2.1.18", - "minimatch": "3.1.2", + "minimatch": "3.1.5", "path-is-inside": "1.0.2", "path-to-regexp": "3.3.0", "range-parser": "1.2.0" @@ -21779,22 +21790,22 @@ "dev": true }, "sinon": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.1.tgz", - "integrity": "sha512-Z0NVCW45W8Mg5oC/27/+fCqIHFnW8kpkFOq0j9XJIev4Ld0mKmERaZv5DMLAb9fGCevjKwaEeIQz5+MBXfZcDw==", + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.3.tgz", + "integrity": "sha512-0x8TQFr8EjADhSME01u1ZK31yv2+bd6Z5NrBCHVM+n4qL1wFqbxftmeyi3bwlr49FbbzRfrqSFOpyHCOh/YmYA==", "dev": true, "requires": { "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^15.1.0", - "@sinonjs/samsam": "^8.0.3", - "diff": "^8.0.2", + "@sinonjs/fake-timers": "^15.1.1", + "@sinonjs/samsam": "^9.0.3", + "diff": "^8.0.3", "supports-color": "^7.2.0" }, "dependencies": { "diff": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", - "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", "dev": true } } @@ -22089,9 +22100,9 @@ } }, "start-server-and-test": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.1.3.tgz", - "integrity": "sha512-k4EcbNjeg0odaDkAMlIeDVDByqX9PIgL4tivgP2tES6Zd8o+4pTq/HgbWCyA3VHIoZopB+wGnNPKYGGSByNriQ==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.1.5.tgz", + "integrity": "sha512-A/SbXpgXE25ScSkpLLqvGvVZT0ykN6+AzS8tVqMBCTxbJy2Nwuen59opT+afalK5aS+AuQmZs0EsLwjnuDN+/g==", "dev": true, "requires": { "arg": "^5.0.2", @@ -22101,7 +22112,7 @@ "execa": "5.1.1", "lazy-ass": "1.6.0", "ps-tree": "1.2.0", - "wait-on": "9.0.3" + "wait-on": "9.0.4" }, "dependencies": { "debug": { @@ -22442,6 +22453,12 @@ } } }, + "tinyexec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", + "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", + "dev": true + }, "tldts": { "version": "7.0.16", "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.16.tgz", @@ -22766,14 +22783,14 @@ } }, "wait-on": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-9.0.3.tgz", - "integrity": "sha512-13zBnyYvFDW1rBvWiJ6Av3ymAaq8EDQuvxZnPIw3g04UqGi4TyoIJABmfJ6zrvKo9yeFQExNkOk7idQbDJcuKA==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-9.0.4.tgz", + "integrity": "sha512-k8qrgfwrPVJXTeFY8tl6BxVHiclK11u72DVKhpybHfUL/K6KM4bdyK9EhIVYGytB5MJe/3lq4Tf0hrjM+pvJZQ==", "dev": true, "requires": { - "axios": "^1.13.2", - "joi": "^18.0.1", - "lodash": "^4.17.21", + "axios": "^1.13.5", + "joi": "^18.0.2", + "lodash": "^4.17.23", "minimist": "^1.2.8", "rxjs": "^7.8.2" } @@ -23015,9 +23032,9 @@ "dev": true }, "yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "dev": true }, "yargs": { From 1d801636f058f2abd885c488baff954872b13846 Mon Sep 17 00:00:00 2001 From: yugo innami <58389827+nami8824@users.noreply.github.com> Date: Tue, 7 Apr 2026 23:29:50 +0900 Subject: [PATCH 24/32] fix(aria-allowed-attr): restrict br and wbr elements to aria-hidden only (#4974) Closes: https://github.com/dequelabs/axe-core/issues/3177 --- doc/standards-object.md | 3 +- .../aria/aria-allowed-attr-elm-evaluate.js | 45 +++++++++ lib/checks/aria/aria-allowed-attr-elm.json | 13 +++ lib/rules/aria-allowed-attr.json | 2 +- lib/standards/html-elms.js | 6 +- locales/_template.json | 7 ++ test/checks/aria/aria-allowed-attr-elm.js | 92 +++++++++++++++++++ .../rules/aria-allowed-attr/failures.html | 3 + .../rules/aria-allowed-attr/failures.json | 4 +- .../rules/aria-allowed-attr/passes.html | 4 + .../rules/aria-allowed-attr/passes.json | 4 +- 11 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 lib/checks/aria/aria-allowed-attr-elm-evaluate.js create mode 100644 lib/checks/aria/aria-allowed-attr-elm.json create mode 100644 test/checks/aria/aria-allowed-attr-elm.js diff --git a/doc/standards-object.md b/doc/standards-object.md index 42766eca3..eb460c179 100644 --- a/doc/standards-object.md +++ b/doc/standards-object.md @@ -95,7 +95,7 @@ The [`htmlElms`](../lib/standards/html-elms.js) object defines valid HTML elemen ### Used by Rules -- `aria-allowed-attr` - Checks if the attribute can be used on the element from the `noAriaAttrs` property. +- `aria-allowed-attr` - Checks if the attribute can be used on the element from the `noAriaAttrs` and `allowedAriaAttrs` properties. - `aria-allowed-role` - Checks if the role can be used on the HTML element from the `allowedRoles` property. - `aria-required-attrs` - Checks if any required attrs are defined implicitly on the element from the `implicitAttrs` property. @@ -110,6 +110,7 @@ The [`htmlElms`](../lib/standards/html-elms.js) object defines valid HTML elemen - `interactive` - `allowedRoles` - boolean or array(required). If element is allowed to use ARIA roles, a value of `true` means any role while a list of roles means only those are allowed. A value of `false` means no roles are allowed. - `noAriaAttrs` - boolean(optional. Defaults `true`). If the element is allowed to use global ARIA attributes and any allowed for the elements role. +- `allowedAriaAttrs` - array(optional). If specified, restricts which ARIA attributes may be used with this element (when no explicit role is set). Used by the `aria-allowed-attr` rule. - `shadowRoot` - boolean(optional. Default `false`). If the element is allowed to have a shadow root. - `implicitAttrs` - object(optional. Default `{}`). Any implicit ARIA attributes for the element and their default value. - `namingMethods` - array(optional. Default `[]`). The [native text method](../lib/commons/text/native-text-methods.js) used to calculate the accessible name of the element. diff --git a/lib/checks/aria/aria-allowed-attr-elm-evaluate.js b/lib/checks/aria/aria-allowed-attr-elm-evaluate.js new file mode 100644 index 000000000..01af3b4f2 --- /dev/null +++ b/lib/checks/aria/aria-allowed-attr-elm-evaluate.js @@ -0,0 +1,45 @@ +import { getExplicitRole } from '../../commons/aria'; +import { getElementSpec, getGlobalAriaAttrs } from '../../commons/standards'; + +export default function ariaAllowedAttrElmEvaluate(node, options, virtualNode) { + const elmSpec = getElementSpec(virtualNode); + + // If no allowedAriaAttrs restriction, this check doesn't apply + if (!elmSpec.allowedAriaAttrs) { + return true; + } + + // If element has an explicit role, defer to the role-based check + const explicitRole = getExplicitRole(virtualNode); + if (explicitRole) { + return true; + } + + const { allowedAriaAttrs } = elmSpec; + const globalAriaAttrs = getGlobalAriaAttrs(); + const invalid = []; + + for (const attrName of virtualNode.attrNames) { + if ( + globalAriaAttrs.includes(attrName) && + !allowedAriaAttrs.includes(attrName) + ) { + invalid.push(attrName); + } + } + + if (!invalid.length) { + return true; + } + + const messageKey = invalid.length > 1 ? 'plural' : 'singular'; + this.data({ + messageKey, + nodeName: virtualNode.props.nodeName, + values: invalid + .map(attrName => attrName + '="' + virtualNode.attr(attrName) + '"') + .join(', ') + }); + + return false; +} diff --git a/lib/checks/aria/aria-allowed-attr-elm.json b/lib/checks/aria/aria-allowed-attr-elm.json new file mode 100644 index 000000000..ebbdf67e9 --- /dev/null +++ b/lib/checks/aria/aria-allowed-attr-elm.json @@ -0,0 +1,13 @@ +{ + "id": "aria-allowed-attr-elm", + "evaluate": "aria-allowed-attr-elm-evaluate", + "metadata": { + "messages": { + "pass": "ARIA attributes are allowed for this element", + "fail": { + "singular": "ARIA attribute is not allowed on ${data.nodeName} elements: ${data.values}", + "plural": "ARIA attributes are not allowed on ${data.nodeName} elements: ${data.values}" + } + } + } +} diff --git a/lib/rules/aria-allowed-attr.json b/lib/rules/aria-allowed-attr.json index d90759692..4ef67632c 100644 --- a/lib/rules/aria-allowed-attr.json +++ b/lib/rules/aria-allowed-attr.json @@ -16,7 +16,7 @@ "description": "Ensure an element's role supports its ARIA attributes", "help": "Elements must only use supported ARIA attributes" }, - "all": ["aria-allowed-attr"], + "all": ["aria-allowed-attr", "aria-allowed-attr-elm"], "any": [], "none": ["aria-unsupported-attr"] } diff --git a/lib/standards/html-elms.js b/lib/standards/html-elms.js index 041d2a943..76e296f21 100644 --- a/lib/standards/html-elms.js +++ b/lib/standards/html-elms.js @@ -133,7 +133,8 @@ const htmlElms = { br: { contentTypes: ['phrasing', 'flow'], allowedRoles: ['presentation', 'none'], - namingMethods: ['titleText', 'singleSpace'] + namingMethods: ['titleText', 'singleSpace'], + allowedAriaAttrs: ['aria-hidden'] }, button: { contentTypes: ['interactive', 'phrasing', 'flow'], @@ -969,7 +970,8 @@ const htmlElms = { }, wbr: { contentTypes: ['phrasing', 'flow'], - allowedRoles: ['presentation', 'none'] + allowedRoles: ['presentation', 'none'], + allowedAriaAttrs: ['aria-hidden'] } }; diff --git a/locales/_template.json b/locales/_template.json index 771d26ef3..7e3304e21 100644 --- a/locales/_template.json +++ b/locales/_template.json @@ -426,6 +426,13 @@ "plural": "Abstract roles cannot be directly used: ${data.values}" } }, + "aria-allowed-attr-elm": { + "pass": "ARIA attributes are allowed for this element", + "fail": { + "singular": "ARIA attribute is not allowed on ${data.nodeName} elements: ${data.values}", + "plural": "ARIA attributes are not allowed on ${data.nodeName} elements: ${data.values}" + } + }, "aria-allowed-attr": { "pass": "ARIA attributes are used correctly for the defined role", "fail": { diff --git a/test/checks/aria/aria-allowed-attr-elm.js b/test/checks/aria/aria-allowed-attr-elm.js new file mode 100644 index 000000000..2d90568e2 --- /dev/null +++ b/test/checks/aria/aria-allowed-attr-elm.js @@ -0,0 +1,92 @@ +describe('aria-allowed-attr-elm', () => { + 'use strict'; + + const queryFixture = axe.testUtils.queryFixture; + const checkContext = axe.testUtils.MockCheckContext(); + + afterEach(() => { + checkContext.reset(); + }); + + it('should pass for br with aria-hidden', () => { + const vNode = queryFixture(''); + + assert.isTrue( + axe.testUtils + .getCheckEvaluate('aria-allowed-attr-elm') + .call(checkContext, null, null, vNode) + ); + }); + + it('should pass for wbr with aria-hidden', () => { + const vNode = queryFixture(''); + + assert.isTrue( + axe.testUtils + .getCheckEvaluate('aria-allowed-attr-elm') + .call(checkContext, null, null, vNode) + ); + }); + + it('should fail for br with disallowed aria attribute', () => { + const vNode = queryFixture('
    '); + + assert.isFalse( + axe.testUtils + .getCheckEvaluate('aria-allowed-attr-elm') + .call(checkContext, null, null, vNode) + ); + assert.deepEqual(checkContext._data, { + messageKey: 'singular', + nodeName: 'br', + values: 'aria-busy="true"' + }); + }); + + it('should fail for wbr with disallowed aria attribute', () => { + const vNode = queryFixture(''); + + assert.isFalse( + axe.testUtils + .getCheckEvaluate('aria-allowed-attr-elm') + .call(checkContext, null, null, vNode) + ); + assert.deepEqual(checkContext._data, { + messageKey: 'singular', + nodeName: 'wbr', + values: 'aria-busy="true"' + }); + }); + + it('should pass for br with non-global aria attribute', () => { + const vNode = queryFixture('
    '); + + assert.isTrue( + axe.testUtils + .getCheckEvaluate('aria-allowed-attr-elm') + .call(checkContext, null, null, vNode) + ); + }); + + it('should pass for br with explicit role', () => { + const vNode = queryFixture( + '
    ' + ); + + assert.isTrue( + axe.testUtils + .getCheckEvaluate('aria-allowed-attr-elm') + .call(checkContext, null, null, vNode) + ); + }); + + it('should pass for element without allowedAriaAttrs restriction', () => { + const vNode = queryFixture('
    '); + + assert.isTrue( + axe.testUtils + .getCheckEvaluate('aria-allowed-attr-elm') + .call(checkContext, null, null, vNode) + ); + }); +}); diff --git a/test/integration/rules/aria-allowed-attr/failures.html b/test/integration/rules/aria-allowed-attr/failures.html index 21c84b0e5..4c582d7d4 100644 --- a/test/integration/rules/aria-allowed-attr/failures.html +++ b/test/integration/rules/aria-allowed-attr/failures.html @@ -13,3 +13,6 @@
    + +
    + diff --git a/test/integration/rules/aria-allowed-attr/failures.json b/test/integration/rules/aria-allowed-attr/failures.json index 02d9579b8..03a4569f5 100644 --- a/test/integration/rules/aria-allowed-attr/failures.json +++ b/test/integration/rules/aria-allowed-attr/failures.json @@ -9,6 +9,8 @@ ["#fail5"], ["#fail6"], ["#fail7"], - ["#fail8"] + ["#fail8"], + ["#fail9"], + ["#fail10"] ] } diff --git a/test/integration/rules/aria-allowed-attr/passes.html b/test/integration/rules/aria-allowed-attr/passes.html index a21c68c3b..3242c3170 100644 --- a/test/integration/rules/aria-allowed-attr/passes.html +++ b/test/integration/rules/aria-allowed-attr/passes.html @@ -2173,3 +2173,7 @@
    + + +
    + diff --git a/test/integration/rules/aria-allowed-attr/passes.json b/test/integration/rules/aria-allowed-attr/passes.json index 0974e0725..6c68e108a 100644 --- a/test/integration/rules/aria-allowed-attr/passes.json +++ b/test/integration/rules/aria-allowed-attr/passes.json @@ -104,6 +104,8 @@ ["#pass99"], ["#pass100"], ["#pass101"], - ["#pass102"] + ["#pass102"], + ["#pass103"], + ["#pass104"] ] } From d5a57050b9aa96048db52910c10f60ef579ff9b7 Mon Sep 17 00:00:00 2001 From: Rin Date: Thu, 9 Apr 2026 23:23:47 +0700 Subject: [PATCH 25/32] refactor(frame-messenger): Guard against inherited properties as topics and channelIds (#5062) Updated `frame-messenger` and `respondable` modules to use `Object.create(null)` for message and topic handler stores. ### Description The current implementation uses plain objects (`{}`) which are susceptible to prototype pollution if untrusted strings like `"__proto__"` are passed as `channelId` or `topic`. By using `Object.create(null)`, these stores become "pure" maps without a prototype, ensuring security and robustness in cross-frame communication. This change is backward compatible and adheres to standard security practices for high-performance JavaScript libraries. Closes: #5062 --- lib/core/utils/frame-messenger/channel-store.js | 6 ++++-- lib/core/utils/respondable.js | 13 +++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/core/utils/frame-messenger/channel-store.js b/lib/core/utils/frame-messenger/channel-store.js index 59ba07878..1cb12256c 100644 --- a/lib/core/utils/frame-messenger/channel-store.js +++ b/lib/core/utils/frame-messenger/channel-store.js @@ -8,14 +8,16 @@ export function storeReplyHandler( sendToParent = true ) { assert( - !channels[channelId], + !Object.prototype.hasOwnProperty.call(channels, channelId), `A replyHandler already exists for this message channel.` ); channels[channelId] = { replyHandler, sendToParent }; } export function getReplyHandler(channelId) { - return channels[channelId]; + return Object.prototype.hasOwnProperty.call(channels, channelId) + ? channels[channelId] + : undefined; } export function deleteReplyHandler(channelId) { diff --git a/lib/core/utils/respondable.js b/lib/core/utils/respondable.js index 7a1c5c4da..cbacaf932 100644 --- a/lib/core/utils/respondable.js +++ b/lib/core/utils/respondable.js @@ -39,7 +39,13 @@ export default function respondable( */ function messageListener(data, responder) { const { topic, message, keepalive } = data; - const topicHandler = topicHandlers[topic]; + const topicHandler = Object.prototype.hasOwnProperty.call( + topicHandlers, + topic + ) + ? topicHandlers[topic] + : undefined; + if (!topicHandler) { return; } @@ -92,7 +98,10 @@ respondable.subscribe = function subscribe(topic, topicHandler) { typeof topicHandler === 'function', 'Subscriber callback must be a function' ); - assert(!topicHandlers[topic], `Topic ${topic} is already registered to.`); + assert( + !Object.prototype.hasOwnProperty.call(topicHandlers, topic), + `Topic ${topic} is already registered to.` + ); topicHandlers[topic] = topicHandler; }; From 5906273841cbd7ac9e08af730dffc244cf42b39b Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Fri, 10 Apr 2026 08:46:42 -0600 Subject: [PATCH 26/32] fix(target-size): ignore position: fixed elements that are offscreen when page is scrolled (#5066) closes #5065 --------- Co-authored-by: Wilco Fiers Co-authored-by: Wilco Fiers --- lib/commons/dom/find-nearby-elms.js | 16 +- lib/commons/dom/index.js | 1 + lib/commons/dom/is-fixed-position.js | 45 +++ lib/commons/dom/is-offscreen.js | 43 +-- test/commons/dom/is-fixed-position.js | 104 ++++++ test/commons/dom/is-offscreen.js | 310 +++++++++++------- test/commons/dom/is-visible.js | 26 ++ .../meta-refresh-pass.js | 1 - .../full/target-size/fixed-scroll.html | 40 +++ .../full/target-size/fixed-scroll.js | 45 +++ .../full/target-size/target-size.js | 1 - .../full/target-size/too-many-rects.js | 1 - .../integration/virtual-rules/summary-name.js | 1 - 13 files changed, 486 insertions(+), 148 deletions(-) create mode 100644 lib/commons/dom/is-fixed-position.js create mode 100644 test/commons/dom/is-fixed-position.js create mode 100644 test/integration/full/target-size/fixed-scroll.html create mode 100644 test/integration/full/target-size/fixed-scroll.js diff --git a/lib/commons/dom/find-nearby-elms.js b/lib/commons/dom/find-nearby-elms.js index a0e421137..b6e69e52b 100644 --- a/lib/commons/dom/find-nearby-elms.js +++ b/lib/commons/dom/find-nearby-elms.js @@ -1,5 +1,5 @@ import getNodeGrid from './get-node-grid'; -import { memoize } from '../../core/utils'; +import isFixedPosition from './is-fixed-position'; export default function findNearbyElms(vNode, margin = 0) { const grid = getNodeGrid(vNode); @@ -7,7 +7,7 @@ export default function findNearbyElms(vNode, margin = 0) { return []; // Elements not in the grid don't have ._grid } const rect = vNode.boundingClientRect; - const selfIsFixed = hasFixedPosition(vNode); + const selfIsFixed = isFixedPosition(vNode); const gridPosition = grid.getGridPositionOfRect(rect, margin); const neighbors = []; @@ -17,7 +17,7 @@ export default function findNearbyElms(vNode, margin = 0) { vNeighbor && vNeighbor !== vNode && !neighbors.includes(vNeighbor) && - selfIsFixed === hasFixedPosition(vNeighbor) + selfIsFixed === isFixedPosition(vNeighbor) ) { neighbors.push(vNeighbor); } @@ -26,13 +26,3 @@ export default function findNearbyElms(vNode, margin = 0) { return neighbors; } - -const hasFixedPosition = memoize(vNode => { - if (!vNode) { - return false; - } - if (vNode.getComputedStylePropertyValue('position') === 'fixed') { - return true; - } - return hasFixedPosition(vNode.parent); -}); diff --git a/lib/commons/dom/index.js b/lib/commons/dom/index.js index 3449238aa..93e3f353a 100644 --- a/lib/commons/dom/index.js +++ b/lib/commons/dom/index.js @@ -28,6 +28,7 @@ export { default as hasLangText } from './has-lang-text'; export { default as idrefs } from './idrefs'; export { default as insertedIntoFocusOrder } from './inserted-into-focus-order'; export { default as isCurrentPageLink } from './is-current-page-link'; +export { default as isFixedPosition } from './is-fixed-position'; export { default as isFocusable } from './is-focusable'; export { default as isHiddenWithCSS } from './is-hidden-with-css'; export { default as isHiddenForEveryone } from './is-hidden-for-everyone'; diff --git a/lib/commons/dom/is-fixed-position.js b/lib/commons/dom/is-fixed-position.js new file mode 100644 index 000000000..d065694cf --- /dev/null +++ b/lib/commons/dom/is-fixed-position.js @@ -0,0 +1,45 @@ +import memoize from '../../core/utils/memoize'; +import { nodeLookup } from '../../core/utils'; + +/** + * Determines if an element is inside a position:fixed subtree, even if the element itself is positioned differently. + * @param {VirtualNode|Element} node + * @param {Boolean} [options.skipAncestors] If the ancestor tree should not be used + * @return {Boolean} The element's position state + */ +export default function isFixedPosition(node, { skipAncestors } = {}) { + const { vNode } = nodeLookup(node); + + // detached element + if (!vNode) { + return false; + } + + if (skipAncestors) { + return isFixedSelf(vNode); + } + + return isFixedAncestors(vNode); +} + +/** + * Check the element for position:fixed + */ +const isFixedSelf = memoize(function isFixedSelfMemoized(vNode) { + return vNode.getComputedStylePropertyValue('position') === 'fixed'; +}); + +/** + * Check the element and ancestors for position:fixed + */ +const isFixedAncestors = memoize(function isFixedAncestorsMemoized(vNode) { + if (isFixedSelf(vNode)) { + return true; + } + + if (!vNode.parent) { + return false; + } + + return isFixedAncestors(vNode.parent); +}); diff --git a/lib/commons/dom/is-offscreen.js b/lib/commons/dom/is-offscreen.js index d0e3b75f7..4883be568 100644 --- a/lib/commons/dom/is-offscreen.js +++ b/lib/commons/dom/is-offscreen.js @@ -2,6 +2,7 @@ import getComposedParent from './get-composed-parent'; import getElementCoordinates from './get-element-coordinates'; import getViewportSize from './get-viewport-size'; import { nodeLookup } from '../../core/utils'; +import isFixedPosition from './is-fixed-position'; function noParentScrolled(element, offset) { element = getComposedParent(element); @@ -37,39 +38,43 @@ function isOffscreen(element, { isAncestor } = {}) { return undefined; } - let leftBoundary; const docElement = document.documentElement; const styl = window.getComputedStyle(domNode); const dir = window .getComputedStyle(document.body || docElement) .getPropertyValue('direction'); - const coords = getElementCoordinates(domNode); + const isFixed = isFixedPosition(domNode); + const coords = isFixed + ? domNode.getBoundingClientRect() + : getElementCoordinates(domNode); + + // Consider 0 height/ width elements at origin visible + if (coords.top === 0 && coords.bottom === 0) { + return false; + } + if (coords.left === 0 && coords.right === 0) { + return false; + } - // bottom edge beyond if ( - coords.bottom < 0 && + coords.bottom <= 0 && (noParentScrolled(domNode, coords.bottom) || styl.position === 'absolute') ) { return true; } - if (coords.left === 0 && coords.right === 0) { - //This is an edge case, an empty (zero-width) element that isn't positioned 'off screen'. - return false; + const viewportSize = getViewportSize(window); + if (isFixed && coords.top >= viewportSize.height) { + return true; // Positioned below the viewport } - if (dir === 'ltr') { - if (coords.right <= 0) { - return true; - } - } else { - leftBoundary = Math.max( - docElement.scrollWidth, - getViewportSize(window).width - ); - if (coords.left >= leftBoundary) { - return true; - } + const rightEdge = Math.max(docElement.scrollWidth, viewportSize.width); + if ((isFixed || dir === 'rtl') && coords.left >= rightEdge) { + return true; // Positioned right of the viewport, preventing right scrolling + } + + if ((isFixed || dir === 'ltr') && coords.right <= 0) { + return true; // Positioned left of the viewport, preventing left scrolling } return false; diff --git a/test/commons/dom/is-fixed-position.js b/test/commons/dom/is-fixed-position.js new file mode 100644 index 000000000..c6ff247e4 --- /dev/null +++ b/test/commons/dom/is-fixed-position.js @@ -0,0 +1,104 @@ +describe('dom.isFixedPosition', () => { + const isFixedPosition = axe.commons.dom.isFixedPosition; + const { queryFixture, queryShadowFixture } = axe.testUtils; + + it('returns true for element with "position: fixed"', () => { + const vNode = queryFixture( + '
    ' + ); + + assert.isTrue(isFixedPosition(vNode)); + }); + + it('returns false for element without position', () => { + const vNode = queryFixture('
    '); + + assert.isFalse(isFixedPosition(vNode)); + }); + + for (const position of ['relative', 'absolute', 'sticky']) { + it(`returns false for element with "position: ${position}"`, () => { + const vNode = queryFixture( + `
    ` + ); + + assert.isFalse(isFixedPosition(vNode)); + }); + } + + it('returns true for ancestor with position: fixed', () => { + const vNode = queryFixture( + '
    ' + ); + + assert.isTrue(isFixedPosition(vNode)); + }); + + it('returns true for ancestor with "position: fixed" even when the element is positioned differently', () => { + const vNode = queryFixture( + '
    ' + ); + + assert.isTrue(isFixedPosition(vNode)); + }); + + it('returns false on detached elements', function () { + var el = document.createElement('div'); + el.innerHTML = 'I am not visible because I am detached!'; + + assert.isFalse(axe.commons.dom.isFixedPosition(el)); + }); + + describe('options.skipAncestors', () => { + it('returns false for ancestor with "position: fixed"', () => { + const vNode = queryFixture( + '
    ' + ); + + assert.isFalse(isFixedPosition(vNode, { skipAncestors: true })); + }); + }); + + describe('Shadow DOM', () => { + it('returns false when no element in the composed tree has position: fixed', () => { + const vNode = queryShadowFixture( + '
    ', + '' + ); + assert.isFalse(isFixedPosition(vNode)); + }); + + it('returns true for element in shadow tree with position: fixed', () => { + const vNode = queryShadowFixture( + '
    ', + '
    ' + ); + + assert.isTrue(isFixedPosition(vNode)); + }); + + it('returns true when ancestor outside shadow tree has position: fixed', () => { + const vNode = queryShadowFixture( + '
    ', + '' + ); + assert.isTrue(isFixedPosition(vNode)); + }); + + it('returns true when ancestor outside shadow is fixed and target in shadow has a different position', () => { + const vNode = queryShadowFixture( + '
    ', + '' + ); + assert.isTrue(isFixedPosition(vNode)); + }); + + it('returns false with skipAncestors when only ancestor outside shadow tree is fixed', () => { + const vNode = queryShadowFixture( + '
    ', + '' + ); + assert.isFalse(isFixedPosition(vNode, { skipAncestors: true })); + }); + }); +}); diff --git a/test/commons/dom/is-offscreen.js b/test/commons/dom/is-offscreen.js index e755eda1a..4455c3a16 100644 --- a/test/commons/dom/is-offscreen.js +++ b/test/commons/dom/is-offscreen.js @@ -1,161 +1,247 @@ -describe('dom.isOffscreen', function () { - 'use strict'; - var fixture = document.getElementById('fixture'); - var shadowSupport = axe.testUtils.shadowSupport; +describe('dom.isOffscreen', () => { + const { isOffscreen } = axe.commons.dom; + const fixture = document.getElementById('fixture'); + const { queryFixture, fixtureSetup, flatTreeSetup, shadowSupport } = + axe.testUtils; - afterEach(function () { - fixture.innerHTML = ''; + afterEach(() => { document.body.style.direction = 'ltr'; }); - it('should detect elements positioned outside the left edge', function () { - fixture.innerHTML = - '
    Offscreen?
    '; - var el = document.getElementById('target'); + after(() => { + window.scrollTo(0, 0); + }); + + it('should be false for 0 height elements at the top of the viewport', () => { + assert.isFalse(isOffscreen(document.body)); + assert.isFalse(isOffscreen(document.documentElement)); + + const vNode = queryFixture('
    '); + assert.isFalse(isOffscreen(vNode)); + }); - assert.isTrue(axe.commons.dom.isOffscreen(el)); + it('should detect elements positioned outside the left edge', () => { + const vNode = queryFixture( + '
    Offscreen?
    ' + ); + assert.isTrue(isOffscreen(vNode)); }); - it('should detect elements positioned to but not beyond the left edge', function () { - fixture.innerHTML = - '
    Offscreen?
    '; - var el = document.getElementById('target'); + it('should detect elements positioned to but not beyond the left edge', () => { + const vNode = queryFixture( + '
    Offscreen?
    ' + ); - assert.isTrue(axe.commons.dom.isOffscreen(el)); + assert.isTrue(isOffscreen(vNode)); }); - it('should not detect elements at the left edge with a zero width', function () { - fixture.innerHTML = - '
    '; - var el = document.getElementById('target'); + it('should not detect elements at the left edge with a zero width', () => { + const vNode = queryFixture( + '
    ' + ); - assert.isFalse(axe.commons.dom.isOffscreen(el)); + assert.isFalse(isOffscreen(vNode)); }); - it('should detect elements positioned outside the top edge', function () { - fixture.innerHTML = - '
    Offscreen?
    '; - var el = document.getElementById('target'); - assert.isTrue(axe.commons.dom.isOffscreen(el)); + it('should detect elements positioned outside the top edge', () => { + const vNode = queryFixture( + '
    Offscreen?
    ' + ); + assert.isTrue(isOffscreen(vNode)); }); - it('should never detect elements positioned outside the bottom edge', function () { - fixture.innerHTML = - '
    Offscreen?
    '; - var el = document.getElementById('target'); + it('should never detect elements positioned outside the bottom edge', () => { + const vNode = queryFixture( + '
    Offscreen?
    ' + ); - assert.isFalse(axe.commons.dom.isOffscreen(el)); + assert.isFalse(isOffscreen(vNode)); }); - it('should detect elements positioned that bleed inside the left edge', function () { - fixture.innerHTML = - '
    Offscreen?
    '; - var el = document.getElementById('target'); + it('should detect elements positioned that bleed inside the left edge', () => { + const vNode = queryFixture( + '
    Offscreen?
    ' + ); - assert.isFalse(axe.commons.dom.isOffscreen(el)); + assert.isFalse(isOffscreen(vNode)); }); - it('should detect elements positioned outside the right edge', function () { - fixture.innerHTML = - '
    Offscreen?
    '; - var el = document.getElementById('target'); + it('should detect elements positioned outside the right edge', () => { + const vNode = queryFixture( + '
    Offscreen?
    ' + ); - assert.isFalse(axe.commons.dom.isOffscreen(el)); + assert.isFalse(isOffscreen(vNode)); }); - it('should detect elements positioned outside the top edge', function () { - fixture.innerHTML = - '
    Offscreen?
    '; - var el = document.getElementById('target'); + it('should detect elements positioned outside the top edge', () => { + const vNode = queryFixture( + '
    Offscreen?
    ' + ); - assert.isFalse(axe.commons.dom.isOffscreen(el)); + assert.isFalse(isOffscreen(vNode)); }); - it('should detect elements positioned outside the bottom edge', function () { - fixture.innerHTML = - '
    Offscreen?
    '; - var el = document.getElementById('target'); + it('should detect elements positioned outside the bottom edge', () => { + const vNode = queryFixture( + '
    Offscreen?
    ' + ); - assert.isFalse(axe.commons.dom.isOffscreen(el)); + assert.isFalse(isOffscreen(vNode)); }); - it('should detect elements that are made off-screen by a parent', function () { - fixture.innerHTML = - '
    ' + - '
    Offscreen?
    ' + - '
    '; - - var el = document.getElementById('target'); + it('should detect elements that are made off-screen by a parent', () => { + const vNode = queryFixture(` +
    +
    Offscreen?
    +
    + `); - assert.isTrue(axe.commons.dom.isOffscreen(el)); + assert.isTrue(isOffscreen(vNode)); }); - it('should NOT detect elements positioned outside the right edge on LTR documents', function () { - fixture.innerHTML = - '
    Offscreen?
    '; - var el = document.getElementById('target'); + it('should NOT detect elements positioned outside the right edge on LTR documents', () => { + const vNode = queryFixture( + '
    Offscreen?
    ' + ); - assert.isFalse(axe.commons.dom.isOffscreen(el)); + assert.isFalse(isOffscreen(vNode)); }); - it('should detect elements positioned outside the right edge on RTL documents', function () { + it('should detect elements positioned outside the right edge on RTL documents', () => { document.body.style.direction = 'rtl'; - fixture.innerHTML = - '
    Offscreen?
    '; - var el = document.getElementById('target'); + const vNode = queryFixture( + '
    Offscreen?
    ' + ); + assert.isTrue(isOffscreen(vNode)); + }); - assert.isTrue(axe.commons.dom.isOffscreen(el)); + it('should NOT detect elements positioned outside the left edge on RTL documents', () => { + document.body.style.direction = 'rtl'; + const vNode = queryFixture( + '
    Offscreen?
    ' + ); + + assert.isFalse(isOffscreen(vNode)); }); - it('should NOT detect elements positioned outside the left edge on RTL documents', function () { + it('should detect elements positioned outside the right edge on RTL documents', () => { document.body.style.direction = 'rtl'; - fixture.innerHTML = - '
    Offscreen?
    '; - var el = document.getElementById('target'); - - assert.isFalse(axe.commons.dom.isOffscreen(el)); - }); - - it('should not detect elements positioned because of a scroll', function () { - fixture.innerHTML = - '
    ' + - '
    goobye
    ' + - '
    high
    ' + - '
    hello
    ' + - '
    '; - var viz = document.getElementById('visible'); - assert.isFalse(axe.commons.dom.isOffscreen(viz)); - var scrollme = document.getElementById('scrollme'); + const vNode = queryFixture( + '
    Offscreen?
    ' + ); + + assert.isTrue(isOffscreen(vNode)); + }); + + it('should not detect elements positioned because of a scroll', () => { + fixtureSetup(` +
    +
    goodbye
    +
    high
    +
    hello
    +
    + `); + const viz = document.getElementById('visible'); + assert.isFalse(isOffscreen(viz)); + const scrollme = document.getElementById('scrollme'); scrollme.scrollIntoView(); - assert.isFalse(axe.commons.dom.isOffscreen(viz)); + assert.isFalse(isOffscreen(viz)); }); - it('should return undefined if actual ndoe is undefined', function () { - assert.isUndefined(axe.commons.dom.isOffscreen()); + it('should return undefined if actual node is undefined', () => { + assert.isUndefined(isOffscreen()); }); - (shadowSupport.v1 ? it : xit)( - 'should detect on screen shadow nodes', - function () { - fixture.innerHTML = '
    '; - var shadow = fixture.querySelector('div').attachShadow({ mode: 'open' }); - shadow.innerHTML = '
    Offscreen?
    '; - - var el = shadow.querySelector('#target'); - assert.isFalse(axe.commons.dom.isOffscreen(el)); - } - ); + (shadowSupport.v1 ? it : xit)('should detect on screen shadow nodes', () => { + fixture.innerHTML = '
    '; + const shadow = fixture.querySelector('div').attachShadow({ mode: 'open' }); + shadow.innerHTML = '
    Offscreen?
    '; + flatTreeSetup(fixture); - (shadowSupport.v1 ? it : xit)( - 'should detect off screen shadow nodes', - function () { - fixture.innerHTML = '
    '; - var shadow = fixture.querySelector('div').attachShadow({ mode: 'open' }); - shadow.innerHTML = - '
    Offscreen?
    '; + const el = shadow.querySelector('#target'); + assert.isFalse(isOffscreen(el)); + }); - var el = shadow.querySelector('#target'); - assert.isTrue(axe.commons.dom.isOffscreen(el)); - } - ); + (shadowSupport.v1 ? it : xit)('should detect off screen shadow nodes', () => { + fixture.innerHTML = '
    '; + const shadow = fixture.querySelector('div').attachShadow({ mode: 'open' }); + shadow.innerHTML = + '
    Offscreen?
    '; + flatTreeSetup(fixture); + + const el = shadow.querySelector('#target'); + assert.isTrue(isOffscreen(el)); + }); + + describe('positioned: fixed', () => { + it('should detect elements positioned outside the top edge', () => { + const vNode = queryFixture( + '
    Offscreen?
    ' + ); + + assert.isTrue(isOffscreen(vNode)); + }); + + it('should detect elements positioned outside the top edge when scrolled', () => { + const vNode = queryFixture(` +
    +
    Offscreen?
    +
    + `); + + assert.isTrue(isOffscreen(vNode)); + window.scrollTo(0, document.body.scrollHeight); + assert.isTrue(isOffscreen(vNode)); + }); + + it('should detect elements positioned outside the bottom edge', () => { + const vNode = queryFixture( + `
    Offscreen?
    ` + ); + assert.isTrue(isOffscreen(vNode)); + }); + + it('should consider elements in the viewport, but beyond the window size as on screen', () => { + const vNode = queryFixture(` +
    +

    Hello World

    +
    + Offscreen? +
    +
    + `); + assert.isFalse(isOffscreen(vNode)); + }); + + it('should detect elements positioned outside the right edge (LTR)', () => { + const vNode = queryFixture( + `
    Offscreen?
    ` + ); + assert.isTrue(isOffscreen(vNode)); + }); + + it('should detect elements positioned outside the right edge (RTL)', () => { + document.body.style.direction = 'rtl'; + const vNode = queryFixture( + `
    Offscreen?
    ` + ); + assert.isTrue(isOffscreen(vNode)); + }); + + it('should detect elements positioned outside the left edge (LTR)', () => { + const vNode = queryFixture( + `
    Offscreen?
    ` + ); + assert.isTrue(isOffscreen(vNode)); + }); + + it('should detect elements positioned outside the left edge on RTL documents', () => { + document.body.style.direction = 'rtl'; + const vNode = queryFixture( + `
    Offscreen?
    ` + ); + assert.isTrue(isOffscreen(vNode)); + }); + }); }); diff --git a/test/commons/dom/is-visible.js b/test/commons/dom/is-visible.js index db85fafc3..7ea710a2a 100644 --- a/test/commons/dom/is-visible.js +++ b/test/commons/dom/is-visible.js @@ -5,6 +5,7 @@ describe('dom.isVisible', function () { var queryFixture = axe.testUtils.queryFixture; var shadowSupported = axe.testUtils.shadowSupport.v1; var computedStyleStub; + var flatTreeSetup = axe.testUtils.flatTreeSetup; afterEach(function () { document.getElementById('fixture').innerHTML = ''; @@ -21,6 +22,7 @@ describe('dom.isVisible', function () { it('should return false if computedStyle return null for whatever reason', function () { computedStyleStub = sinon.stub(window, 'getComputedStyle').returns(null); var el = document.createElement('div'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -28,6 +30,7 @@ describe('dom.isVisible', function () { fixture.innerHTML = '
    Hello!
    '; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isTrue(axe.commons.dom.isVisible(el)); }); @@ -36,6 +39,7 @@ describe('dom.isVisible', function () { '
    hi
    '; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isTrue(axe.commons.dom.isVisible(el)); }); @@ -44,6 +48,7 @@ describe('dom.isVisible', function () { '
    StickySticky
    '; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isTrue(axe.commons.dom.isVisible(el)); }); @@ -53,6 +58,7 @@ describe('dom.isVisible', function () { '
    Hi
    ' + '
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isTrue(axe.commons.dom.isVisible(el)); }); @@ -60,6 +66,7 @@ describe('dom.isVisible', function () { fixture.innerHTML = '
Hi
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -67,6 +74,7 @@ describe('dom.isVisible', function () { fixture.innerHTML = '
Hi
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -110,6 +118,7 @@ describe('dom.isVisible', function () { '
Hi
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isTrue(axe.commons.dom.isVisible(el)); }); @@ -118,6 +127,7 @@ describe('dom.isVisible', function () { ''; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isTrue(axe.commons.dom.isVisible(el)); }); @@ -128,6 +138,7 @@ describe('dom.isVisible', function () { '
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isTrue(axe.commons.dom.isVisible(el)); }); @@ -138,6 +149,7 @@ describe('dom.isVisible', function () { '
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isTrue(axe.commons.dom.isVisible(el)); }); @@ -153,6 +165,7 @@ describe('dom.isVisible', function () { fixture.innerHTML = '
Hi
'; el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -168,6 +181,7 @@ describe('dom.isVisible', function () { fixture.innerHTML = '
Hi
'; el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -182,6 +196,7 @@ describe('dom.isVisible', function () { fixture.innerHTML = '
Hi
'; el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isTrue(axe.commons.dom.isVisible(el)); }); @@ -198,6 +213,7 @@ describe('dom.isVisible', function () { '
' + '
Hi
' + '
'; el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -213,6 +229,7 @@ describe('dom.isVisible', function () { '
' + '
Hi
' + '
'; el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isTrue(axe.commons.dom.isVisible(el)); }); @@ -228,6 +245,7 @@ describe('dom.isVisible', function () { fixture.innerHTML = '
Hi
'; el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -235,6 +253,7 @@ describe('dom.isVisible', function () { fixture.innerHTML = ''; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -242,6 +261,7 @@ describe('dom.isVisible', function () { fixture.innerHTML = '
Hello!
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -249,6 +269,7 @@ describe('dom.isVisible', function () { fixture.innerHTML = '
Hello!
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -257,6 +278,7 @@ describe('dom.isVisible', function () { '
Hello!
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -265,6 +287,7 @@ describe('dom.isVisible', function () { '
Hello!
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -342,6 +365,7 @@ describe('dom.isVisible', function () { '
Hi
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -352,6 +376,7 @@ describe('dom.isVisible', function () { '
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); @@ -403,6 +428,7 @@ describe('dom.isVisible', function () { '
StickySticky
'; var el = document.getElementById('target'); + flatTreeSetup(fixture); assert.isFalse(axe.commons.dom.isVisible(el)); }); }); diff --git a/test/integration/full/meta-refresh-no-exceptions/meta-refresh-pass.js b/test/integration/full/meta-refresh-no-exceptions/meta-refresh-pass.js index 6cd665da3..c663d3af6 100644 --- a/test/integration/full/meta-refresh-no-exceptions/meta-refresh-pass.js +++ b/test/integration/full/meta-refresh-no-exceptions/meta-refresh-pass.js @@ -3,7 +3,6 @@ describe('meta-refresh-no-exceptions pass', function () { it('should pass', function (done) { axe.run({ runOnly: 'meta-refresh-no-exceptions' }, function (err, results) { - console.log(results); try { assert.isNull(err); assert.lengthOf(results.violations, 0, 'violations'); diff --git a/test/integration/full/target-size/fixed-scroll.html b/test/integration/full/target-size/fixed-scroll.html new file mode 100644 index 000000000..0be7c89b2 --- /dev/null +++ b/test/integration/full/target-size/fixed-scroll.html @@ -0,0 +1,40 @@ + + + + Target-size position: fixed and scrolled + + + + + + + +
+ +
+

+ +

+

+ +

+
+ + + + + diff --git a/test/integration/full/target-size/fixed-scroll.js b/test/integration/full/target-size/fixed-scroll.js new file mode 100644 index 000000000..e68bcbaf8 --- /dev/null +++ b/test/integration/full/target-size/fixed-scroll.js @@ -0,0 +1,45 @@ +describe('target-size position: fixed and scrolled', () => { + 'use strict'; + let results; + + before(done => { + axe.testUtils.awaitNestedLoad(() => { + window.scrollTo(0, document.body.scrollHeight); + const options = { + runOnly: ['target-size'], + elementRef: true + }; + const context = { + // ignore the mocha links + exclude: '#mocha' + }; + axe.run(context, options, (err, r) => { + if (err) { + return done(err); + } + results = r; + done(); + }); + }); + }); + + describe('violations', function () { + it('should find 0', function () { + assert.lengthOf(results.violations, 0); + }); + }); + + describe('passes', function () { + it('should find 2', function () { + assert.lengthOf(results.passes[0].nodes, 2); + }); + }); + + it('should find 0 inapplicable', function () { + assert.lengthOf(results.inapplicable, 0); + }); + + it('should find 0 incomplete', function () { + assert.lengthOf(results.incomplete, 0); + }); +}); diff --git a/test/integration/full/target-size/target-size.js b/test/integration/full/target-size/target-size.js index 68287e6a8..42256a5fb 100644 --- a/test/integration/full/target-size/target-size.js +++ b/test/integration/full/target-size/target-size.js @@ -29,7 +29,6 @@ describe('target-size test', function () { results.passes[0].nodes.forEach(function (node) { node.element.className += ' passes'; }); - console.log(results); done(); }); }); diff --git a/test/integration/full/target-size/too-many-rects.js b/test/integration/full/target-size/too-many-rects.js index d81485024..1effc114d 100644 --- a/test/integration/full/target-size/too-many-rects.js +++ b/test/integration/full/target-size/too-many-rects.js @@ -18,7 +18,6 @@ describe('target-size too many rects test', () => { done(err); } results = r; - console.log(results); done(); }); }); diff --git a/test/integration/virtual-rules/summary-name.js b/test/integration/virtual-rules/summary-name.js index 1c711bd77..38d7ac311 100644 --- a/test/integration/virtual-rules/summary-name.js +++ b/test/integration/virtual-rules/summary-name.js @@ -26,7 +26,6 @@ describe('summary-name virtual-rule', () => { vSummary.children = []; appendSerialChild(vDetails, vSummary); const results = axe.runVirtualRule('summary-name', vSummary); - console.log(results); assert.lengthOf(results.passes, 0); assert.lengthOf(results.violations, 1); assert.lengthOf(results.incomplete, 0); From 3ab66ba865bd35067bba49461daff93bb9256303 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Mon, 13 Apr 2026 11:26:45 -0600 Subject: [PATCH 27/32] chore(release): 4.11.3 --- CHANGELOG.md | 7 +++++++ bower.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- sri-history.json | 4 ++++ 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33d846e41..6f693aa3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [4.11.3](https://github.com/dequelabs/axe-core/compare/v4.11.2...v4.11.3) (2026-04-13) + +### Bug Fixes + +- **aria-allowed-attr:** restrict br and wbr elements to aria-hidden only ([#4974](https://github.com/dequelabs/axe-core/issues/4974)) ([1d80163](https://github.com/dequelabs/axe-core/commit/1d801636f058f2abd885c488baff954872b13846)) +- **target-size:** ignore position: fixed elements that are offscreen when page is scrolled ([#5066](https://github.com/dequelabs/axe-core/issues/5066)) ([5906273](https://github.com/dequelabs/axe-core/commit/5906273841cbd7ac9e08af730dffc244cf42b39b)), closes [#5065](https://github.com/dequelabs/axe-core/issues/5065) + ### [4.11.2](https://github.com/dequelabs/axe-core/compare/v4.11.1...v4.11.2) (2026-03-30) ### Bug Fixes diff --git a/bower.json b/bower.json index 8469cdf9a..cdcf5df69 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "axe-core", - "version": "4.11.2", + "version": "4.11.3", "deprecated": true, "contributors": [ { diff --git a/package-lock.json b/package-lock.json index 2d03b3175..4bd9814ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "axe-core", - "version": "4.11.2", + "version": "4.11.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "axe-core", - "version": "4.11.2", + "version": "4.11.3", "license": "MPL-2.0", "devDependencies": { "@axe-core/webdriverjs": "^4.10.2", diff --git a/package.json b/package.json index 239cdd068..918e2522e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "axe-core", "description": "Accessibility engine for automated Web UI testing", - "version": "4.11.2", + "version": "4.11.3", "license": "MPL-2.0", "engines": { "node": ">=4" diff --git a/sri-history.json b/sri-history.json index ad8030df6..4bf35a11c 100644 --- a/sri-history.json +++ b/sri-history.json @@ -406,5 +406,9 @@ "4.11.2": { "axe.js": "sha256-l0az3GGxixpCq0IHsMxs3F4nvNGl/89Ypf8icbh6Xfk=", "axe.min.js": "sha256-dacAeIgHzdkplnXlC66fYnqfnzaOkpb+pxf3Ejreyxo=" + }, + "4.11.3": { + "axe.js": "sha256-MgD9sqZmQpnqTg+i7glZ32Zo9TQZ81mOpgg0HABdwoE=", + "axe.min.js": "sha256-BWVH7wRf9Q7eSaVMmaNWiQ/4lAxUFqVKnJEAhsVFM90=" } } From 6e68d0a5d26999b996152df82238bc3f3a041cb3 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Wed, 22 Apr 2026 08:06:23 -0600 Subject: [PATCH 28/32] fix(utils/getAncestry): escape node name (#5079) Closes: #5078 --- lib/core/utils/get-ancestry.js | 3 ++- test/core/utils/get-ancestry.js | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/core/utils/get-ancestry.js b/lib/core/utils/get-ancestry.js index 5652c69ac..c5b1fd2d5 100644 --- a/lib/core/utils/get-ancestry.js +++ b/lib/core/utils/get-ancestry.js @@ -1,7 +1,8 @@ +import escapeSelector from './escape-selector'; import getShadowSelector from './get-shadow-selector'; function generateAncestry(node) { - const nodeName = node.nodeName.toLowerCase(); + const nodeName = escapeSelector(node.nodeName.toLowerCase()); const parentElement = node.parentElement; const parentNode = node.parentNode; diff --git a/test/core/utils/get-ancestry.js b/test/core/utils/get-ancestry.js index 8f570e907..bfd419d96 100644 --- a/test/core/utils/get-ancestry.js +++ b/test/core/utils/get-ancestry.js @@ -71,4 +71,31 @@ describe('axe.utils.getAncestry', () => { 'div:nth-child(2)' ]); }); + + it('escapes the node name', () => { + fixture.innerHTML = ` +
+ + + +
+ + + + `; + + const sel1 = axe.utils.getAncestry(document.querySelector('#target1')); + assert.equal( + sel1, + 'html > body > div:nth-child(1) > div:nth-child(1) > hello\\=\\"world\\" > button' + ); + assert.isNotNull(document.querySelector(sel1)); + + const sel2 = axe.utils.getAncestry(document.querySelector('#target2')); + assert.equal( + sel2, + 'html > body > div:nth-child(1) > emoji-👍:nth-child(2) > button' + ); + assert.isNotNull(document.querySelector(sel2)); + }); }); From fb8508052f16feb1736c54f8dc0ab32865c1ca0f Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Thu, 23 Apr 2026 11:11:00 -0600 Subject: [PATCH 29/32] chore: fix cherry-pick script buffer size error for large git logs (#5071) This fixes the cherry-pick script's problem of trying to read git log information now that we have too many for the current buffer size. Originally done in https://github.com/dequelabs/axe-core/pull/5048 but porting to it's own pr since that one was closed. --- build/cherry-pick.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build/cherry-pick.js b/build/cherry-pick.js index f8040807b..c5575f364 100755 --- a/build/cherry-pick.js +++ b/build/cherry-pick.js @@ -5,6 +5,9 @@ const conventionalCommitsParser = require('conventional-commits-parser'); const chalk = require('chalk'); const { version } = require('../package.json'); +// Node's default execSync buffer (~1 MiB) is too small for `git log` on long histories. +const GIT_LOG_EXEC_OPTS = { maxBuffer: 50 * 1024 * 1024 }; + const releaseType = process.argv[2]; let ignoreCommits = process.argv[3]; @@ -50,7 +53,8 @@ function getCommits(branch) { // all commits are too large for execSync buffer size so we'll just get since the last 3 years const date = new Date(new Date().setFullYear(new Date().getFullYear() - 3)); const stdout = execSync( - `git log ${branch || ''} --abbrev-commit --since=${date.getFullYear()}` + `git log ${branch || ''} --no-merges --abbrev-commit --since=${date.getFullYear()}`, + GIT_LOG_EXEC_OPTS ).toString(); const allCommits = stdout .split(/commit (?=[\w\d]{8}[\n\r])/) From df34adfc1967919d667d40a76ab5c85b6e47ddfe Mon Sep 17 00:00:00 2001 From: yugo innami <58389827+nami8824@users.noreply.github.com> Date: Fri, 24 Apr 2026 02:22:19 +0900 Subject: [PATCH 30/32] fix(commons/text): exclude natively hidden elements from aria-labelledby accessible name (#5076) Fixes accessible name calculation to correctly exclude `