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 1/7] 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

[![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 7988fcc0c5..9c9ec6cf0e 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 2/7] 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 9c9ec6cf0e..4e484e9a73 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 3/7] 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 fcdf925de4..2d03b3175f 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 4/7] 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 42766eca38..eb460c1795 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 0000000000..01af3b4f28 --- /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 0000000000..ebbdf67e96 --- /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 d907596925..4ef67632c1 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 041d2a9438..76e296f212 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 771d26ef37..7e3304e215 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 0000000000..2d90568e2f --- /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 21c84b0e50..4c582d7d4d 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 02d9579b81..03a4569f50 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 a21c68c3b1..3242c31707 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 0974e07250..6c68e108ab 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 5/7] 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 59ba07878f..1cb12256c2 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 7a1c5c4da8..cbacaf9328 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 6/7] 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 a0e421137c..b6e69e52be 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 3449238aa1..93e3f353a6 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 0000000000..d065694cfa --- /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 d0e3b75f71..4883be5688 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 0000000000..c6ff247e44 --- /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 e755eda1a2..4455c3a16f 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 db85fafc3c..7ea710a2af 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 6cd665da31..c663d3af6d 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 0000000000..0be7c89b28 --- /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 0000000000..e68bcbaf8d --- /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 68287e6a8b..42256a5fbb 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 d814850247..1effc114d9 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 1c711bd77c..38d7ac3119 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 7/7] 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 33d846e41d..6f693aa3b5 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 8469cdf9ac..cdcf5df692 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 2d03b3175f..4bd9814ced 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 239cdd0683..918e2522e8 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 ad8030df6f..4bf35a11c9 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=" } }