diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 63acb7fc21..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,458 +0,0 @@ -version: 2.1 - -defaults: &defaults - working_directory: ~/axe-core - -unix_box: &unix_box - docker: - - image: cimg/node:22.16-browsers - -unix_nightly_box: &unix_nightly_box - docker: - - image: cimg/node:lts-browsers - -orbs: - puppeteer: threetreeslight/puppeteer@0.1.2 - browser-tools: circleci/browser-tools@1.5.1 - -set_npm_auth: &set_npm_auth - run: npm config set "//registry.npmjs.org/:_authToken" $NPM_AUTH - -restore_dependency_cache_unix: &restore_dependency_cache_unix - restore_cache: - name: Restore NPM Cache - keys: - - v9-cache-unix-{{ checksum "package-lock.json" }} - -restore_build: &restore_build - restore_cache: - name: Restore Axe.js Cache - keys: - - v9-cache-build-<< pipeline.git.revision >> - -commands: - browser-tools-job: - steps: - - browser-tools/install-browser-tools - -jobs: - # Fetch and cache dependencies. - dependencies_unix: - <<: *defaults - <<: *unix_box - steps: - - checkout - - <<: *restore_dependency_cache_unix - - run: - name: Skip Install If Cache Exists - command: | - if [ -d "node_modules" ]; then - echo "node_modules exist" - circleci step halt - else - echo "node_modules does not exist" - fi - - browser-tools-job - - <<: *set_npm_auth - - run: npm ci - - run: npx browser-driver-manager install chromedriver --verbose - - save_cache: - key: v9-cache-unix-{{ checksum "package-lock.json" }} - paths: - - node_modules - - # Build and cache built files - build_unix: - <<: *defaults - <<: *unix_box - steps: - - checkout - - <<: *restore_dependency_cache_unix - - run: npm run prepare - - run: npm run build - - save_cache: - key: v9-cache-build-<< pipeline.git.revision >> - paths: - - axe.js - - axe.min.js - - # Run ESLINT - lint: - <<: *defaults - <<: *unix_box - steps: - - checkout - - <<: *restore_dependency_cache_unix - - run: npm run eslint - - # Run the test suite. - test_chrome: - <<: *defaults - <<: *unix_box - steps: - - checkout - - browser-tools-job - - <<: *restore_dependency_cache_unix - - run: npx browser-driver-manager install chromedriver --verbose - - <<: *restore_build - - run: npm run test -- --browsers Chrome - - run: npm run test:integration:chrome - - test_firefox: - <<: *defaults - <<: *unix_box - steps: - - checkout - - browser-tools-job - - <<: *restore_dependency_cache_unix - - <<: *restore_build - - run: npm run test -- --browsers Firefox - - run: npm run test:integration:firefox - - # Run examples under `doc/examples` - test_examples: - <<: *defaults - <<: *unix_box - steps: - - checkout - - browser-tools-job - - <<: *restore_dependency_cache_unix - - run: npx browser-driver-manager install chromedriver --verbose - - <<: *restore_build - - run: npm run test:examples - - # Run ACT test cases - test_act: - <<: *defaults - <<: *unix_box - steps: - - checkout - - browser-tools-job - - <<: *restore_dependency_cache_unix - - run: npx browser-driver-manager install chromedriver --verbose - - <<: *restore_build - - run: npm run test:act - - # Run ARIA practices test cases - test_aria_practices: - <<: *defaults - <<: *unix_box - steps: - - checkout - - browser-tools-job - - <<: *restore_dependency_cache_unix - - run: npx browser-driver-manager install chromedriver --verbose - - <<: *restore_build - - run: npm run test:apg - - # Test locale files - test_locales: - <<: *defaults - <<: *unix_box - steps: - - checkout - - browser-tools-job - - <<: *restore_dependency_cache_unix - - run: npx browser-driver-manager install chromedriver --verbose - - <<: *restore_build - - run: npm run test:locales - - # Test virtual rules - test_virtual_rules: - <<: *defaults - <<: *unix_box - steps: - - checkout - - browser-tools-job - - <<: *restore_dependency_cache_unix - - run: npx browser-driver-manager install chromedriver --verbose - - <<: *restore_build - - run: npm run test:virtual-rules - - # Run the test suite for nightly builds. - test_nightly_browsers: - <<: *defaults - <<: *unix_nightly_box - steps: - - checkout - - <<: *restore_dependency_cache_unix - - run: sudo apt-get update -y - - <<: *restore_build - - run: - name: Install Chrome and ChromeDriver Beta - command: npx browser-driver-manager install chrome=beta chromedriver=beta --verbose - - run: - name: Install Firefox Nightly - command: | - # Assumes Firefox >= 135; in earlier versions, this resolves to a .tar.bz2 instead - wget -O firefox-nightly.tar.xz "https://download.mozilla.org/?product=firefox-nightly-latest-ssl&os=linux64&lang=en-US" - tar xf firefox-nightly.tar.xz - - run: - name: Set Environment Variable - command: echo "export FIREFOX_NIGHTLY_BIN=$(pwd)/firefox/firefox-bin" >> $BASH_ENV - - run: npm run test -- --browsers Chrome,FirefoxNightly - - # Run the test suite for nightly builds. - test_nightly_act: - <<: *defaults - <<: *unix_nightly_box - steps: - - checkout - - <<: *restore_dependency_cache_unix - - browser-tools-job - # install ACT rules - # install first as for some reason installing a single package - # also re-installs all repo dependencies as well - - run: npm install w3c/wcag-act-rules#main - - run: npx browser-driver-manager install chromedriver --verbose - - <<: *restore_build - - run: npm run test:act - - # Run the test suite for nightly builds. - test_nightly_aria_practices: - <<: *defaults - <<: *unix_nightly_box - steps: - - checkout - - <<: *restore_dependency_cache_unix - - browser-tools-job - # install ARIA practices - # install first as for some reason installing a single package - # also re-installs all repo dependencies as well - - run: npm install w3c/aria-practices#main - - run: npx browser-driver-manager install chromedriver --verbose - - <<: *restore_build - - run: npm run test:apg - - # Test api docs can be built - build_api_docs: - <<: *defaults - <<: *unix_box - steps: - - checkout - - <<: *restore_dependency_cache_unix - - run: npm run api-docs - - # Test newest axe-core version rule help docs are active (only on - # master prs) - test_rule_help_version: - <<: *defaults - <<: *unix_box - steps: - - checkout - - <<: *restore_dependency_cache_unix - - run: npm run test:rule-help-version - - # Test jsdom API - test_jsdom: - <<: *defaults - <<: *unix_box - steps: - - checkout - - <<: *restore_dependency_cache_unix - - <<: *restore_build - - run: npm run test:jsdom - - # Release a "next" version - next_release: - <<: *defaults - <<: *unix_box - steps: - - checkout - - <<: *set_npm_auth - - <<: *restore_dependency_cache_unix - - <<: *restore_build - - run: npm run next-release - - run: .circleci/verify-release.sh - - run: npm publish --tag=next - - # Release a "production" version - verify_sri: - <<: *defaults - <<: *unix_box - steps: - - checkout - - <<: *set_npm_auth - - <<: *restore_dependency_cache_unix - - <<: *restore_build - - run: npm run sri-validate - - # Release a "production" version - release: - <<: *defaults - <<: *unix_box - steps: - - checkout - - <<: *set_npm_auth - - <<: *restore_dependency_cache_unix - - <<: *restore_build - - run: .circleci/verify-release.sh - - run: npm publish - - # Create a GitHub release. - github_release: - docker: - - image: cimg/go:1.17.1 - steps: - - checkout - - run: go get gopkg.in/aktau/github-release.v0 - - run: - name: Download and run GitHub release script - command: | - curl https://raw.githubusercontent.com/dequelabs/attest-release-scripts/develop/src/node-github-release.sh -s -o ./node-github-release.sh - chmod +x ./node-github-release.sh - ./node-github-release.sh - - # Verify released package has all required files - verify_release: - <<: *defaults - <<: *unix_box - steps: - - checkout - - <<: *restore_dependency_cache_unix - - run: .circleci/verify-release.sh post - - # Verify canary released package has all required files - verify_next_release: - <<: *defaults - <<: *unix_box - steps: - - checkout - - <<: *restore_dependency_cache_unix - - run: npm run next-release - - run: .circleci/verify-release.sh post - -workflows: - version: 2 - build: - jobs: - # install deps - - dependencies_unix - - build_unix: - requires: - - dependencies_unix - # Run linting - - lint: - requires: - - dependencies_unix - # Run tests on all commits, but after installing dependencies - - test_chrome: - requires: - - build_unix - - test_firefox: - requires: - - build_unix - - test_examples: - requires: - - build_unix - - test_act: - requires: - - build_unix - - test_aria_practices: - requires: - - build_unix - - test_locales: - requires: - - build_unix - - test_virtual_rules: - requires: - - build_unix - - build_api_docs: - requires: - - build_unix - - test_rule_help_version: - requires: - - build_unix - - test_jsdom: - requires: - - build_unix - # Verify the sri history is correct - - verify_sri: - requires: - - build_unix - filters: - branches: - only: - - /^release-.+/ - - master - # Hold for approval - - hold_release: - type: approval - requires: - - test_chrome - - test_firefox - - test_examples - - test_act - - test_aria_practices - - test_locales - - test_virtual_rules - - build_api_docs - - test_rule_help_version - - test_jsdom - - verify_sri - filters: - branches: - only: - - master - # Run a next release on "develop" commits, but only after the tests pass and dependencies are installed - - next_release: - requires: - - test_chrome - - test_firefox - - test_examples - - test_act - - test_aria_practices - - test_locales - - test_virtual_rules - - build_api_docs - - test_rule_help_version - - test_jsdom - filters: - branches: - only: develop - # Run a production release on "master" commits, but only after the tests pass and dependencies are installed - - release: - requires: - - hold_release - filters: - branches: - only: master - # Verify releases have all required files - - verify_release: - requires: - - release - filters: - branches: - only: master - - verify_next_release: - requires: - - next_release - filters: - branches: - only: develop - - github_release: - requires: - - release - nightly: - triggers: - - schedule: - # run at 00:00 UTC every day - cron: '0 0 * * *' - filters: - branches: - only: - - develop - jobs: - - dependencies_unix - - build_unix: - requires: - - dependencies_unix - - test_nightly_browsers: - requires: - - build_unix - - test_nightly_act: - requires: - - build_unix - - test_nightly_aria_practices: - requires: - - build_unix diff --git a/.circleci/verify-release.sh b/.circleci/verify-release.sh deleted file mode 100755 index 93a350f06c..0000000000 --- a/.circleci/verify-release.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash - -set -e - -# Verifying the release can fail due to race condition of -# npm not publishing the package before we try to install -# it -function wait_for_publish() { - echo "Installing $1@$2" - - set +e - for i in {1..10}; do - npm install "$1@$2" 2> /dev/null - if [ $? -eq 0 ]; then - echo "Successfully installed" - set -e - return - else - echo "Retrying..." - sleep 10 - fi - done - - echo "Unable to install. Exiting..." - exit 1 -} - -if [ -n "$1" ] && [ "$1" == "post" ] -then - # verify the released npm package in another dir as we can't - # install a package with the same name - version=$(node -pe "require('./package.json').version") - name=$(node -pe "require('./package.json').name") - - mkdir "verify-release-$version" - cd "verify-release-$version" - npm init -y - - wait_for_publish "$name" "$version" - - node -pe "window={}; document={}; require('$name')" - - cd "node_modules/${name}" -else - # verify main file exists - main=$(node -pe "require('./package.json').main") - node -pe "window={}; document={}; require('./$main')" -fi - -# Test if typescript file exists (if declared) -# -# Note: because we are using node to read the package.json, the -# variable gets set to the string `undefined` if the property -# does not exists, rather than an empty variable. -types=$(node -pe "require('./package.json').types") -if [ "$types" == "undefined" ] -then - types=$(node -pe "require('./package.json').typings") -fi - -if [ "$types" != "undefined" ] && [ ! -f "$types" ] -then - echo "types file missing" - exit 1; -fi \ No newline at end of file diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index df541335e0..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,12 +0,0 @@ -**/node_modules/* -**/tmp/* - -build/tasks/aria-supported.js - -doc/api/* -doc/examples/jest_react/*.js - -lib/core/imports/*.js -lib/core/utils/uuid.js -axe.js -axe.min.js diff --git a/.github/actions/install-deps/action.yml b/.github/actions/install-deps/action.yml new file mode 100644 index 0000000000..b7d220b7f6 --- /dev/null +++ b/.github/actions/install-deps/action.yml @@ -0,0 +1,78 @@ +name: 'Install Dependencies' +description: 'Install OS and Project dependencies' + +inputs: + node-version: + description: 'Node.js version to install' + required: false + start-xvfb: + description: 'If provided, this is the display number to run xvfb on. Should be in `:N` format, e.g., `:99`.' + required: false + nightly: + description: 'If true, installs the nightly versions of browsers.' + required: false +outputs: + chrome-path: + description: 'Path to the installed Chrome binary' + value: ${{ steps.setup-chrome.outputs.chrome-path }} + firefox-path: + description: 'Path to the installed Firefox binary' + value: ${{ steps.setup-firefox.outputs.firefox-path }} + chromedriver-path: + description: 'Path to the installed ChromeDriver binary' + value: ${{ steps.setup-chrome.outputs.chromedriver-path }} + chrome-version: + description: 'Version of the installed Chrome binary' + value: ${{ steps.setup-chrome.outputs.chrome-version }} + chromedriver-version: + description: 'Version of the installed ChromeDriver binary' + value: ${{ steps.setup-chrome.outputs.chromedriver-version }} + firefox-version: + description: 'Version of the installed Firefox binary' + value: ${{ steps.setup-firefox.outputs.firefox-version }} + +runs: + using: 'composite' + steps: + - name: Setup Node.js + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + registry-url: 'https://registry.npmjs.org' + node-version: ${{ inputs.node-version }} + node-version-file: ${{ inputs.node-version == '' && '.nvmrc' || '' }} + cache: npm + - name: Fix Chrome Sandbox Permissions + shell: bash + run: | + sudo chown root:root /opt/google/chrome/chrome-sandbox + sudo chmod 4755 /opt/google/chrome/chrome-sandbox + - name: Install Xvfb + shell: bash + if: ${{ inputs.start-xvfb }} + run: | + sudo apt-get update + sudo apt-get install -y xvfb x11-xserver-utils + - name: Install Google Chrome for Testing + id: setup-chrome + uses: browser-actions/setup-chrome@b94431e051d1c52dcbe9a7092a4f10f827795416 # v2.1.0 + with: + chrome-version: ${{ inputs.nightly == 'true' && 'beta' || 'stable' }} + install-chromedriver: true + install-dependencies: true + - name: Install Firefox + id: setup-firefox + uses: browser-actions/setup-firefox@5914774dda97099441f02628f8d46411fcfbd208 # v1.7.0 + with: + firefox-version: ${{ inputs.nightly == 'true' && 'latest-nightly' || 'latest' }} + - name: Install Project Dependencies + shell: bash + run: npm ci + - name: Start Xvfb + if: ${{ inputs.start-xvfb }} + env: + DISPLAY: ${{ inputs.start-xvfb }} + shell: bash + # This is the same resolution as what CircleCI used. + # Maintaining it for consistency between the environments + # since something may be resolution dependent. + run: Xvfb "$DISPLAY" -screen 0 1280x1024x24 & diff --git a/.github/bin/determine-version.sh b/.github/bin/determine-version.sh new file mode 100755 index 0000000000..076e7a77b8 --- /dev/null +++ b/.github/bin/determine-version.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -eo pipefail + +echo "::group::Determining new prerelease version" + +NAME=$(npm pkg get name | tr -d '"') +LATEST_VERSION=$(npm pkg get version | tr -d '"') + +SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7) +NEW_VERSION="$LATEST_VERSION-canary.${SHORT_SHA}" + +echo "Latest version in package.json: $LATEST_VERSION" +echo "New prerelease version: $NEW_VERSION" + +echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT" +echo "name=$NAME" >> "$GITHUB_OUTPUT" + +echo "::endgroup::" diff --git a/.github/bin/validate-npm-deploy.sh b/.github/bin/validate-npm-deploy.sh new file mode 100755 index 0000000000..0e2029b5f2 --- /dev/null +++ b/.github/bin/validate-npm-deploy.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +set -eo pipefail + +if [ -z "$PACKAGE_NAME" ] || [ -z "$VERSION" ]; then + echo "::error::PACKAGE_NAME and VERSION environment variables must be set." + exit 1 +fi + +NPM_ROOT_PATH=$(npm root -g) + +npm install -g "${PACKAGE_NAME}@${VERSION}" || { + echo "::error::✗ Failed to install package: ${PACKAGE_NAME}@${VERSION}" + exit 1 +} + +cd "$NPM_ROOT_PATH" || { + echo "::error::✗ Failed to change directory to global npm root: $NPM_ROOT_PATH" + exit 1 +} + +node -pe "window={}; document={}; require('${PACKAGE_NAME}');" || { + echo "::error::✗ Failed to import CommonJS module for package: ${PACKAGE_NAME}" + exit 1 +} + +cd "${NPM_ROOT_PATH}/${PACKAGE_NAME}" || { + echo "::error::✗ Failed to change directory to package path: ${NPM_ROOT_PATH}/${PACKAGE_NAME}" + exit 1 +} + +types=$(node -pe "require('./package.json').types") +if [ "$types" == "undefined" ] +then + types=$(node -pe "require('./package.json').typings") +fi +if [ "$types" != "undefined" ] && [ ! -f "$types" ] +then + echo "::error::The types file is missing" + exit 1; +fi +echo "Types file '$types' is present in the package" diff --git a/.github/bin/validate-package.mjs b/.github/bin/validate-package.mjs new file mode 100755 index 0000000000..c8afd16de8 --- /dev/null +++ b/.github/bin/validate-package.mjs @@ -0,0 +1,441 @@ +#!/usr/bin/env node + +/** + * @fileoverview Validates the package before publishing. + * This script performs several checks to ensure the package + * is correctly set up, including: + * - Verifying the existence of files listed in `package.json`'s `files` array. + * - Ensuring the package can be imported using both ESM `import` and CommonJS `require()`. + * - Validating Subresource Integrity (SRI) hashes for the built files. + * + * The script generates a summary report compatible with + * GitHub Actions, providing detailed feedback on each + * validation step. + * + * Running this script locally has a few implications to be + * aware of: + * 1. It links and unlinks the package globally. So this + * could impact other workspaces where current links are used. + * 2. To test the step summary, set the `GITHUB_STEP_SUMMARY` + * environment variable to a file path. If this file does not + * exist, it will be created. + */ + +import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { createRequire } from 'node:module'; +import { access, appendFile, readFile } from 'node:fs/promises'; +import { execSync } from 'node:child_process'; +import pkg from '../../package.json' with { type: 'json' }; + +const isDebug = process.env.DEBUG === 'true'; +const repoRoot = resolve(import.meta.dirname, '..', '..'); +/** + * Start the exit code at 0 for a successful run. If any checks + * fail, we increment by 1 for each failure. When every check is done, + * we exit with the final exit code. + * + * This means our exit code informs us of how many failures happened. + * + * For anyone unfamiliar with exit codes in shell programs, + * an exit code of `0` means success, and any non-zero exit code + * means failure. + * + * Special note as well, in theory this _could_ go above `255`, + * causing the actual exit code to wrap around back to `0` and + * keep counting. But, if we have that many checks in here down + * the road then all the validation will need a major refactor. + */ +let exitCode = 0; +const missing = []; +const summaryFile = process.env.GITHUB_STEP_SUMMARY; +let summary = `# Package Validation + +
+
Package Name
+
${pkg.name}
+
Package Version
+
${pkg.version}
+
License
+
${pkg.license}
+
+ +`; + +console.group('Package Information'); +console.log('Name:', pkg.name); +console.log('Version:', pkg.version); +console.log('License:', pkg.license); +console.groupEnd(); + +/** + * Checks if a file or folder exists on the filesystem. + * + * @param {string} path - The path to check (relative to repo root) + * @returns {Promise} True if the path exists, false otherwise + */ +const exists = async path => { + const absolutePath = resolve(repoRoot, path); + try { + await access(absolutePath); + return true; + } catch { + return false; + } +}; + +/** + * Appends text to the GitHub Actions step summary file if it + * exists. This is mostly useful for local testing where the + * summary file may not be set. However if we want to set it + * for testing, we can. + * + * Since we build the summary in chunks, this function + * appends the current summary and then clears it for the + * next section. + * + * @param {string} text - The text to append to the summary file + * @returns {Promise} + */ +const appendToSummaryFile = async text => { + if (summaryFile) { + await appendFile(summaryFile, text); + summary = ''; + } +}; + +/** + * Verifies that all files and folders listed in the `files` + * array of `package.json` exist in the repository. + */ +const fileExistenceCheck = async () => { + summary += ` +\n## File Existence Check + +The following results table shows the status of files and folders +listed in the \`files\` array of \`package.json\`. + +> [!NOTE] +> This check only validates the existence of files and folders +> defined. It does not validate the contents. Thus a folder +> could exist but be empty and still pass this check. Or +> a file could exist but have incorrect syntax. + +| File | Status |\n|------|--------| +`; + + console.log('Checking for existence of package files:'); + + for (const file of pkg.files) { + if (await exists(file)) { + console.info(`✓ ${file}`); + summary += `| \`${file}\` | ✓ Found |\n`; + } else { + console.error(`✗ ${file}`); + summary += `| \`${file}\` | ✗ Missing |\n`; + missing.push(file); + } + } + + await appendToSummaryFile(summary); + + if (missing.length > 0) { + await appendToSummaryFile( + `\n**ERROR: Missing files: ${missing.join(', ')}**\n` + ); + console.error(`::error::Missing files: ${missing.join(', ')}`); + exitCode++; + } +}; + +/** + * Validates that the main package file can be loaded via + * CommonJS require. This ensures backward compatibility + * for projects using CommonJS. + */ +const validateCommonJS = async () => { + summary += `\n## CommonJS Compatibility Check + +This check validates that the main package file can be loaded +using CommonJS \`require()\`, ensuring backward compatibility. + +| File | Status | Version |\n|------|--------|--------| +`; + + const require = createRequire(import.meta.url); + + console.log('Validating CommonJS compatibility:'); + + try { + const axe = require(`${pkg.name}`); + + if (!axe || typeof axe !== 'object') { + throw new Error('Module did not export an object'); + } + + if (!axe.version) { + throw new Error('Missing version property'); + } + + console.info(`✓ ${pkg.name} (CommonJS)`); + summary += `| \`${pkg.name}\` | ✓ CommonJS Compatible | ${axe.version} |\n`; + } catch (error) { + console.error(`✗ ${pkg.name} (CommonJS):`, error.message); + summary += `| \`${pkg.name}\` | ✗ CommonJS Failed | Not Found |\n`; + summary += `\n\`\`\`\n${error.message}\n\`\`\`\n`; + exitCode++; + } + + await appendToSummaryFile(summary); +}; + +/** + * Validates that the package and all files listed in the + * `files` array of `package.json` can be imported using + * ESM `import` statements. + */ +const validateImportable = async () => { + summary += `\n## Importable Check + +This check attempts to import the package. As well as all +defined files in the \`files\` array of \`package.json\`. + +> [!NOTE] +> This check fails anything that resolves to \`node_modules\`, +> this is because \`axe-core\` should be linked before +> this is called. When \`exports\` can be added to the +> package definition, then we can self reference imports and +> the link will no longer be required. + +| File | Status | Version |\n|------|--------|--------| +`; + + const importTargets = [...pkg.files.map(file => `${pkg.name}/${file}`)]; + let anyCaught = false; + + console.log('Validating package files are importable:'); + + try { + const axe = await import(pkg.name); + console.info(`✓ ${pkg.name}`); + + if (!axe.default?.version) { + throw new Error('Missing version property'); + } + + summary += `| \`${pkg.name}\` | ✓ Importable | ${axe.default.version} |\n`; + } catch { + console.error(`✗ ${pkg.name}`); + summary += `| \`${pkg.name}\` | ✗ Not Importable | Not Found |\n`; + anyCaught = true; + } + + for (const target of importTargets) { + // Skip things that can't be imported directly + // One day we can hopefully import anything as bytes to validate. + // Ref: https://github.com/tc39/proposal-import-bytes + if ( + target.endsWith('.txt') || + target.endsWith('/') || + target.endsWith('.d.ts') + ) { + continue; + } + + // `import.meta.resolve` is used here to determine + // where the import would be resolved from, following + // any symlinks. Since this package is linked, it + // should never have `node_modules` in the resolved + // path. It *could* happen if a dev is writing code + // within a parent folder named as such, but that is + // unsafe anyways. + // ------------------------------------------------- + // If this is ever setup to run in the post-deploy + // test, then this will cause issues as that runs + // from this folder specifically. + if (import.meta.resolve(target).includes('node_modules')) { + exitCode++; + summary += `| \`${target}\` | ✗ Resolves to node_modules |\n`; + console.error(`✗ ${target} resolves to node_modules`); + continue; + } + + try { + let version = ''; + if (target.endsWith('.json')) { + const data = await import(target, { with: { type: 'json' } }); + version = Object.keys(data.default).at(-1); + } else { + const axe = await import(target); + + if (!axe.default?.version) { + throw new Error('Missing version property'); + } + + version = axe.default.version; + } + console.info(`✓ ${target}`); + summary += `| \`${target}\` | ✓ Importable | ${version} |\n`; + } catch (error) { + console.error(`✗ ${target}`); + summary += `| \`${target}\` | ✗ Not Importable | Not Found |\n`; + summary += `\n\`\`\`\n${error.message}\n\`\`\`\n`; + anyCaught = true; + } + } + + if (anyCaught) { + exitCode++; + } + + await appendToSummaryFile(summary); +}; + +/** + * When a PR targets `master` or a `release-*` branch, + * or these branches are pushed to, we run SRI validation. + * Otherwise, it is skipped since the SRI hashes are only + * updated when releasing. + * + * The history file is deprecated. However, until it is removed + * we should be prudent and continue to validate it. + */ +const validateSriHashes = async () => { + const currentBranch = + process.env.GITHUB_REF_NAME || process.env.GITHUB_HEAD_REF || ''; + + if (!/^release-.+/.test(currentBranch) && currentBranch !== 'master') { + console.log(`Skipping SRI validation (current branch: ${currentBranch})`); + return; + } + + summary += `\n## Subresource Integrity Check + +This check validates the current build against the SRI hash +for the version defined in \`sri-history.json\`. + +| File | Status | +|------|--------| +`; + + const sriHistory = await import(`${pkg.name}/sri-history.json`, { + with: { type: 'json' } + }); + const expectedSri = sriHistory.default[pkg.version]; + // calculate the SRI hash for `axe.js` and `axe.min.js` + // Using `sri-toolbox` as that is what is used in the build process + const { generate } = await import('sri-toolbox'); + + const filesToCheck = [ + { + name: 'axe.js', + path: fileURLToPath(import.meta.resolve(`${pkg.name}/axe.js`)) + }, + { + name: 'axe.min.js', + path: fileURLToPath(import.meta.resolve(`${pkg.name}/axe.min.js`)) + } + ]; + const mismatches = []; + + for (const file of filesToCheck) { + const calculatedSri = generate( + { algorithms: ['sha256'] }, + await readFile(file.path) + ); + + console.log(`Expected SRI for ${file.name}:`, expectedSri[file.name]); + console.log(`Calculated SRI for ${file.name}:`, calculatedSri); + if (calculatedSri !== expectedSri[file.name]) { + console.error(`✗ ${file.name}`); + summary += `| \`${file.name}\` | ✗ Invalid SRI |\n`; + mismatches.push({ + name: file.name, + expected: expectedSri[file.name], + calculated: calculatedSri + }); + continue; + } + + console.info(`✓ ${file.name}`); + summary += `| \`${file.name}\` | ✓ Valid SRI |\n`; + } + + if (mismatches.length > 0) { + summary += `\n### SRI Mismatches\n\n`; + + for (const mismatch of mismatches) { + summary += `**${mismatch.name}:**\n`; + summary += `- Expected: \`${mismatch.expected}\`\n`; + summary += `- Calculated: \`${mismatch.calculated}\`\n\n`; + } + + exitCode++; + } + + await appendToSummaryFile(summary); +}; + +// Start running checks that don't require linking first. +await fileExistenceCheck(); + +/** + * @type {import('child_process').ExecSyncOptionsWithBufferEncoding} + */ +const execOptions = { + cwd: repoRoot, + stdio: isDebug ? 'inherit' : 'pipe', + timeout: 200000 +}; + +console.log('Creating npm link for package validation...'); + +try { + // Link the package globally, then update the package + // internally to use the linked version. + // This is needed because we don't have `exports` defined + // yet, so self referencing imports won't work. + // We also have a circular dependency on the package. + // That means if we try to resolve the import without + // linking, it will resolve the version in `node_modules` + // from npm. + execSync('npm link', execOptions); + execSync(`npm link ${pkg.name}`, execOptions); + + // Run any checks that require the package to reference itself. + await validateCommonJS(); + await validateImportable(); + await validateSriHashes(); +} catch (error) { + console.error('Failed to create npm link:', error.message); + await appendToSummaryFile(` + ## Failed to create npm link + +
Click to expand error details + + \n\`\`\`\n${error.message}\n\`\`\`\n + +
+ + This failure prevented running critical validation checks. + Therefore the entire validation has failed. + `); + console.error(`Failed to create npm link: ${error.message}`); + exitCode++; +} + +console.log('Removing npm link...'); +try { + execSync(`npm unlink ${pkg.name}`, execOptions); + execSync('npm unlink -g', execOptions); +} catch (error) { + // Not a hard failure if unlinking fails since all these + // checks are last. As long as they completed fine, + // validation is acceptable. + // This is more for when running locally to test if + // something goes wrong. As the developer's machine state + // is impacted and they need to know about it. + console.error('Failed to remove npm link:', error.message); +} + +process.exit(exitCode); diff --git a/.github/bin/wait-for-npm-ready.sh b/.github/bin/wait-for-npm-ready.sh new file mode 100755 index 0000000000..245f8abf72 --- /dev/null +++ b/.github/bin/wait-for-npm-ready.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +set -eo pipefail + +if [ -z "$VERSION" ] || [ -z "$PACKAGE_NAME" ]; then + echo "✗ ERROR: VERSION and PACKAGE_NAME environment variables must be set." + exit 1 +fi + +SLEEP_SECONDS=${SLEEP_SECONDS:-10} +MAX_ATTEMPTS=${MAX_ATTEMPTS:-30} + +echo "::group::Waiting for ${PACKAGE_NAME}@${VERSION} to be available on npm registry..." + +for i in $(seq 1 "$MAX_ATTEMPTS"); do + echo "Attempt $i of $MAX_ATTEMPTS..." + + if npm view "${PACKAGE_NAME}@${VERSION}" version > /dev/null 2>&1; then + PUBLISHED_VERSION=$(npm view "${PACKAGE_NAME}@${VERSION}" version) + echo "✓ Package ${PACKAGE_NAME}@${PUBLISHED_VERSION} is now available on npm!" + echo "::endgroup::" + exit 0 + fi + + if [ "$i" -lt "$MAX_ATTEMPTS" ]; then + echo "Package not yet available, waiting ${SLEEP_SECONDS} seconds..." + sleep "$SLEEP_SECONDS" + fi +done + +echo "✗ Timeout: Package ${PACKAGE_NAME}@${VERSION} not available after $((MAX_ATTEMPTS * SLEEP_SECONDS)) seconds" +echo "::endgroup::" + +exit 1 diff --git a/.github/bin/wait-for-workflow-success.sh b/.github/bin/wait-for-workflow-success.sh new file mode 100755 index 0000000000..7ba2246e59 --- /dev/null +++ b/.github/bin/wait-for-workflow-success.sh @@ -0,0 +1,199 @@ +#!/usr/bin/env bash + +# This script waits for a specified GitHub Actions workflow to complete successfully. +# Debug mode can be enabled by setting the DEBUG environment variable to "true". +# Exit codes are as follows: +# 0 - Workflow completed successfully +# 1 - Workflow completed with failure +# 2 - Missing required tools on the host system +# 3 - Missing required environment variables for configuration +# 20 - Timeout waiting for workflow to complete + +set -eo pipefail + +if ! command -v jq &> /dev/null; then + echo "::error::jq is not installed. Please install jq to use this script." + exit 2 +fi + +if ! command -v gh &> /dev/null; then + echo "::error::GitHub CLI (gh) is not installed. Please install gh to use this script." + exit 2 +fi + +if [ -z "$REPOSITORY" ]; then + echo "::error::REPOSITORY environment variable must be set." + exit 3 +fi + +if [ -z "$SHA" ]; then + echo "::error::SHA environment variable must be set." + exit 3 +fi + +if [ -z "$WORKFLOW_NAME" ]; then + echo "::error::WORKFLOW_NAME environment variable must be set." + exit 3 +fi + +if [ -z "$BRANCH" ]; then + echo "::error::BRANCH environment variable must be set." + exit 3 +fi + +# When running locally for testing, this might be forgotten to get set. +# Create a temp file just so there is something to write to that will get thrown away. +if [ -z "$GITHUB_STEP_SUMMARY" ]; then + GITHUB_STEP_SUMMARY=$(mktemp) +fi + +echo "Waiting for '$WORKFLOW_NAME' workflow to complete for commit $SHA" + +# If not provided, default to 5 minutes for the job runner to time out. +TIMEOUT_MINUTES=${TIMEOUT_MINUTES:-5} +# Round down if given a fractional number by just removing the decimal portion. +TIMEOUT_MINUTES=${TIMEOUT_MINUTES%.*} +sleep_seconds=30 +max_attempts=$(( (TIMEOUT_MINUTES * 60) / sleep_seconds )) +attempt=0 + +# We *could* do `status=success` as a query parameter. But then we lose visibility +# into "in-progress" for debugging purposes to at least know if it found a run +# while waiting. +# Ref: https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-repository +api_url="repos/$REPOSITORY/actions/runs?head_sha=$SHA&branch=$BRANCH&exclude_pull_requests=true&event=push" + +# This jq filter can seem complicated. So here is the breakdown: +# 1. `.workflow_runs` - Get the array of workflow runs from the API response +# 2. `sort_by(.created_at) | reverse` - Sort the runs by creation date in descending order. Since the API has no guaranteed order. +# 3. `[.[] | select(.name == "'"$WORKFLOW_NAME"'")][0]` - Filter the runs to only include those with the specified workflow name. Then take the first one (most recent) +# 4. `{status: .status, conclusion: .conclusion}` - Extract only the status and conclusion fields. Since we know this is the most recent run, we only care about these fields later. +# 5. `select(. != null)` - Ensure that we only get a result if there is a matching workflow run +jq_filter='.workflow_runs | sort_by(.created_at) | reverse | [.[] | select(.name == "'"$WORKFLOW_NAME"'")][0] | {status: .status, conclusion: .conclusion} | select(. != null)' + +cat >> "$GITHUB_STEP_SUMMARY" <> "$GITHUB_STEP_SUMMARY" +} + +while [ "$attempt" -lt "$max_attempts" ]; do + # Redirect errors to /dev/null to avoid unusable data in the variable in case of failure. + # If we seem to be having issues in CI later, it would be valuable to setup debugging to log to $GITHUB_STEP_SUMMARY. + workflow_data=$(gh api "$api_url" --jq "$jq_filter" 2>"$log_output" || echo "") + + if [ -z "$workflow_data" ]; then + echo "Attempt $((attempt + 1))/$max_attempts - Workflow run not found yet" + else + status=$(echo "$workflow_data" | jq -r '.status') + conclusion=$(echo "$workflow_data" | jq -r '.conclusion') + + echo "Attempt $((attempt + 1))/$max_attempts - Status: $status, Conclusion: $conclusion" + + if [ "$status" = "completed" ]; then + # Write the result to the summary file + function writeResultToSummary() { + cat >> "$GITHUB_STEP_SUMMARY" <> "$GITHUB_STEP_SUMMARY" < [!TIP] +> Re-running this workflow with debug mode enabled will capture API error logs to help diagnose issues. + +> [!WARNING] +> This can typically indicate that GitHub Action runners are experiencing delays. +> Please check the [GitHub Status Page](https://www.githubstatus.com/) for any ongoing incidents. +> If the status is normal, or if it already is, wait a little bit before re-running the workflow. + +> [!CAUTION] +> If another commit is already deployed, then do *not* re-run this deployment workflow. +> Re-running this would cause an older commit to be the next tag. +> If multiple deployments are failed in a row, then re-run them sequentially as the incident is resolved. + +EOF +writeLogToSummary + +echo "::error::Timeout waiting for '$WORKFLOW_NAME' workflow to complete" +exit 20 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4ed3712ff4..c74cbed1fe 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -44,12 +44,16 @@ updates: # @see https://github.com/dequelabs/axe-core/issues/4428 - dependency-name: 'colorjs.io' versions: ['>0.4.3'] - # Still need to support node 18 + # Still need to support node 18 in our tests - dependency-name: 'glob' versions: ['>=11.0.0'] # Use node 4 types for backward compatibility - dependency-name: '@types/node' versions: ['>=5.0.0'] + # Breaking change that we need to handle in its own pr first + # @see https://github.com/dequelabs/axe-core/pull/4264 + - dependency-name: 'css-selector-parser' + versions: ['>=2.0.0'] groups: # Any updates not caught by the group config will get individual PRs npm-low-risk: diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000000..fda5a9dec2 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,197 @@ +# Do not rename this file. The name "deploy.yml" is known to +# npm for trusted OIDC publishing. +name: Deploy + +on: + # Run on push and not `workflow_run` after tests finish. + # Specifically because `workflow_run` only runs from the context + # of the default branch, regardless of which branch triggered the tests. + # That means no non-default branches could deploy. + push: + branches: + - master + - develop + +concurrency: + group: deploy/${{ github.ref_name }} + cancel-in-progress: false + +permissions: + contents: read + +jobs: + # Since we can't run against `workflow_run`, we have to + # wait for for the Tests to succeed first before any + # processing can happen. + wait-for-tests: + name: Wait for Tests to Pass + if: github.repository_owner == 'dequelabs' + runs-on: ubuntu-24.04 + permissions: + contents: read + actions: read + statuses: read + timeout-minutes: 15 + steps: + - &checkout + name: Checkout repository + timeout-minutes: 2 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + with: + persist-credentials: false + - name: Wait for Tests workflow to complete + timeout-minutes: 13 + env: + SHA: ${{ github.sha }} + REPOSITORY: ${{ github.repository }} + BRANCH: ${{ github.ref_name }} + WORKFLOW_NAME: Tests + DEBUG: ${{ runner.debug == '1' }} + # One minute less than the job timeout to allow for the script to do cleanup work. + TIMEOUT_MINUTES: 12 + GH_TOKEN: ${{ github.token }} + run: ./.github/bin/wait-for-workflow-success.sh + deploy-next: + name: Deploy "next" to npm + needs: wait-for-tests + if: ${{ github.ref_name == 'develop' }} + environment: + name: registry.npmjs.org + permissions: + contents: read + id-token: write # Required for OIDC + runs-on: ubuntu-24.04 + outputs: + version: ${{ steps.determine-version.outputs.version }} + packageName: ${{ steps.determine-version.outputs.name }} + steps: + - *checkout + - &setup-node + name: Setup NodeJS + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + registry-url: 'https://registry.npmjs.org' + node-version-file: .nvmrc + cache: npm + - &install-project-deps + name: Install Project Dependencies + shell: bash + run: npm ci + - &build + name: Build + run: | + npm run prepare + npm run build + - name: Determine prerelease version + id: determine-version + run: ./.github/bin/determine-version.sh + - name: Bump version + env: + NEW_VERSION: ${{ steps.determine-version.outputs.version }} + run: npm version "$NEW_VERSION" --no-git-tag-version --ignore-scripts + - &validate-package + name: Validate package is consumable + env: + # Ref: https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#runner-context + # Linting shows this context might be invalid, but it shouldn't be per docs. + # Probably something missing in the schema. + DEBUG: ${{ runner.debug == '1' }} + run: node .github/bin/validate-package.mjs + - name: Publish "next" version to npm + run: npm publish --tag=next + validate-next-deploy: + name: Validate Next Deployment + needs: deploy-next + runs-on: ubuntu-24.04 + steps: + - *checkout + - *setup-node + # In theory since this is a new job now, by the time + # this would kick off the package should be available. + # But, to be safe in case of delays in propagation, + # we'll implement a retry mechanism. + - name: Wait for package to be available on npm + env: + VERSION: ${{ needs.deploy-next.outputs.version }} + PACKAGE_NAME: ${{ needs.deploy-next.outputs.packageName }} + run: ./.github/bin/wait-for-npm-ready.sh + - name: Validate installation of "next" version + env: + PACKAGE_NAME: ${{ needs.deploy-next.outputs.packageName }} + VERSION: ${{ needs.deploy-next.outputs.version }} + run: ./.github/bin/validate-npm-deploy.sh + prod-hold: + name: Await approval to deploy to production + needs: wait-for-tests + if: ${{ github.ref_name == 'master' }} + environment: + name: production-hold + runs-on: ubuntu-24.04 + steps: + - name: Awaiting approval to deploy to production + run: echo "Approval granted to proceed to production deployment." + prod-deploy: + name: Deploy stable to npm + needs: prod-hold + if: ${{ needs.prod-hold.result == 'success' }} + environment: + name: registry.npmjs.org + permissions: + contents: read + id-token: write # Required for OIDC + outputs: + version: ${{ steps.get-data.outputs.version }} + packageName: ${{ steps.get-data.outputs.name }} + runs-on: ubuntu-24.04 + steps: + - *checkout + - *setup-node + - *install-project-deps + - *build + - *validate-package + - name: Publish stable version to npm + run: npm publish + - name: Get published package data + id: get-data + run: | + VERSION=$(npm pkg get version | tr -d '"') + NAME=$(npm pkg get name | tr -d '"') + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "name=$NAME" >> $GITHUB_OUTPUT + create-github-release: + name: Create GitHub Release + needs: prod-deploy + runs-on: ubuntu-24.04 + permissions: + contents: write # Required to create releases + steps: + - *checkout + - name: Install Release Helper + run: go install gopkg.in/aktau/github-release.v0@latest + - name: Download Release Script + run: curl https://raw.githubusercontent.com/dequelabs/attest-release-scripts/develop/src/node-github-release.sh -s -o ./node-github-release.sh + - name: Make Release Script Executable + run: chmod +x ./node-github-release.sh + - name: Create GitHub Release + run: ./node-github-release.sh + validate-deploy: + name: Validate Deployment + needs: prod-deploy + runs-on: ubuntu-24.04 + steps: + - *checkout + - *setup-node + # In theory since this is a new job now, by the time + # this would kick off the package should be available. + # But, to be safe in case of delays in propagation, + # we'll implement a retry mechanism. + - name: Wait for package to be available on npm + env: + VERSION: ${{ needs.prod-deploy.outputs.version }} + PACKAGE_NAME: ${{ needs.prod-deploy.outputs.packageName }} + run: ./.github/bin/wait-for-npm-ready.sh + - name: Validate installation of stable version + env: + PACKAGE_NAME: ${{ needs.prod-deploy.outputs.packageName }} + VERSION: ${{ needs.prod-deploy.outputs.version }} + run: ./.github/bin/validate-npm-deploy.sh diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index ac74027593..545beb920f 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -14,12 +14,12 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.ref }} - name: Install dependencies run: npm ci - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version-file: .nvmrc cache: 'npm' @@ -29,6 +29,6 @@ jobs: - run: npm run fmt # Prevent the prettierignore change from being committed. - run: git checkout .prettierignore - - uses: stefanzweifel/git-auto-commit-action@778341af668090896ca464160c2def5d1d1a3eb0 # tag=v5 + - uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # tag=v5 with: commit_message: ':robot: Automated formatting fixes' diff --git a/.github/workflows/nightly-tests.yml b/.github/workflows/nightly-tests.yml new file mode 100644 index 0000000000..ab4cf3fd79 --- /dev/null +++ b/.github/workflows/nightly-tests.yml @@ -0,0 +1,81 @@ +name: Nightly Tests + +on: + schedule: + # Runs every day at 2:17 AM UTC + # Schedules should try to be offset from common times + # to avoid high contention times on GitHub runners. + - cron: '17 2 * * *' + workflow_dispatch: + +env: + CHROME_DEVEL_SANDBOX: /opt/google/chrome/chrome-sandbox + +permissions: + contents: read + +jobs: + browsers: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + DISPLAY: ':99' + steps: + - &checkout + name: Checkout repository + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + with: + persist-credentials: false + - name: Install Dependencies + id: install-deps + uses: ./.github/actions/install-deps + with: + nightly: 'true' + start-xvfb: ${{ env.DISPLAY }} + - &build + name: Build + id: build + run: | + npm run prepare + npm run build + - name: Run Firefox Nightly Browser Tests + env: + FIREFOX_NIGHTLY_BIN: ${{ steps.install-deps.outputs.firefox-path }} + run: npm run test -- --browsers FirefoxNightly + - name: Run Chrome Beta Browser Tests + if: ${{ !cancelled() && steps.build.conclusion == 'success' }} + env: + CHROME_BIN: ${{ steps.install-deps.outputs.chrome-path }} + CHROMEDRIVER_BIN: ${{ steps.install-deps.outputs.chromedriver-path }} + run: npm run test -- --browsers Chrome + act: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - *checkout + - &install-deps + name: Install Deps + id: install-deps + uses: ./.github/actions/install-deps + - *build + - name: Install Latest WCAG ACT Rules + run: npm install w3c/wcag-act-rules#main + - name: Run ACT Tests + env: + CHROME_BIN: ${{ steps.install-deps.outputs.chrome-path }} + CHROMEDRIVER_BIN: ${{ steps.install-deps.outputs.chromedriver-path }} + run: npm run test:act + aria-practices: + runs-on: ubuntu-24.04 + timeout-minutes: 7 + steps: + - *checkout + - *install-deps + - *build + - name: Install Latest W3C Aria Practices + run: npm install w3c/aria-practices#main + - name: Run ARIA Practices Tests + env: + CHROME_BIN: ${{ steps.install-deps.outputs.chrome-path }} + CHROMEDRIVER_BIN: ${{ steps.install-deps.outputs.chromedriver-path }} + run: npm run test:apg diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a2b765b7fb..ad707b7f5a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,10 +7,10 @@ jobs: name: Create release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 0 - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version-file: .nvmrc cache: 'npm' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fb7ba06ac8..7988fcc0c5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,51 +6,244 @@ on: branches: - master - develop + - release-* + +# We want to group to the workflow for each branch. +# Non-push events will be cancelled if a new one is started. +# Push events will run sequentially. This helps ensure that +# the `next` tag isn't out of sync. +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: {} + +env: + CHROME_DEVEL_SANDBOX: /opt/google/chrome/chrome-sandbox jobs: - build: - runs-on: ubuntu-latest - timeout-minutes: 5 + lint: + runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 + - &checkout + name: Checkout repository + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + with: + persist-credentials: false + - &setup-node + name: Set up Node.js + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: node-version-file: .nvmrc cache: 'npm' - - run: npm ci - - run: npm run prepare - - run: npm run build - - uses: actions/upload-artifact@v4 + - &install-deps-directly + name: Install Dependencies + run: npm ci + - name: Run ESLint + run: npm run eslint + + fmt_check: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - *checkout + - *setup-node + - *install-deps-directly + - run: npm run fmt:check + + build: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - *checkout + - *setup-node + - *install-deps-directly + - &build + name: Build + run: | + npm run prepare + npm run build + - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: axe-core path: axe.js retention-days: 1 - fmt_check: - runs-on: ubuntu-latest - timeout-minutes: 5 + test_chrome: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + DISPLAY: :99 steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 + - *checkout + - &install-deps-with-xvfb + name: Install Deps + uses: ./.github/actions/install-deps + id: install-deps with: - node-version-file: .nvmrc - cache: 'npm' - - run: npm ci - - run: npm run fmt:check + start-xvfb: ${{ env.DISPLAY }} + - *build + - name: Run Tests Against Chrome + env: + CHROME_BIN: ${{ steps.install-deps.outputs.chrome-path }} + CHROMEDRIVER_BIN: ${{ steps.install-deps.outputs.chromedriver-path }} + run: npm run test -- --browsers Chrome + - name: Run Chrome Integration Tests + env: + CHROME_BIN: ${{ steps.install-deps.outputs.chrome-path }} + CHROMEDRIVER_BIN: ${{ steps.install-deps.outputs.chromedriver-path }} + run: npm run test:integration:chrome + + test_firefox: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + DISPLAY: :99 + steps: + - *checkout + - *install-deps-with-xvfb + - *build + - name: Run Tests Against Firefox + env: + FIREFOX_BIN: ${{ steps.install-deps.outputs.firefox-path }} + run: npm run test -- --browsers Firefox + - name: Run Firefox Integration Tests + env: + FIREFOX_BIN: ${{ steps.install-deps.outputs.firefox-path }} + run: npm run test:integration:firefox + + # Run examples under `doc/examples` + test_examples: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - *checkout + - &install-deps + name: Install Deps + id: install-deps + uses: ./.github/actions/install-deps + - *build + - name: Run Tests Against Examples + run: npm run test:examples + + test_act: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + needs: build + steps: + - *checkout + - *install-deps + - &restore-axe-build + name: Restore axe build + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + with: + name: axe-core + - name: Run ACT Tests + env: + CHROME_BIN: ${{ steps.install-deps.outputs.chrome-path }} + CHROMEDRIVER_BIN: ${{ steps.install-deps.outputs.chromedriver-path }} + run: npm run test:act + + test_aria_practices: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + needs: build + steps: + - *checkout + - *install-deps + - *restore-axe-build + - name: Run ARIA Practices Tests + env: + CHROME_BIN: ${{ steps.install-deps.outputs.chrome-path }} + CHROMEDRIVER_BIN: ${{ steps.install-deps.outputs.chromedriver-path }} + run: npm run test:apg + + test_locales: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + needs: build + steps: + - *checkout + - *install-deps + - *restore-axe-build + - name: Run Locale Tests + run: npm run test:locales + + test_virtual_rules: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + needs: build + steps: + - *checkout + - *install-deps + - *restore-axe-build + - name: Run Virtual Rules Tests + run: npm run test:virtual-rules + + test_jsdom: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + needs: build + steps: + - *checkout + - *install-deps + - *restore-axe-build + - name: Run jsdom Tests + run: npm run test:jsdom + + build_api_docs: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - *checkout + - *install-deps + - name: Run API Docs Build + run: npm run api-docs + + test_rule_help_version: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + if: ${{ github.ref_name == 'master' }} + steps: + - *checkout + - *install-deps + - name: Run Rule Help Version Tests + run: npm run test:rule-help-version + + sri-validate: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + needs: build + # Run on master and RC branches along with PRs targeting those branches. + if: ${{ github.ref_name == 'master' || startsWith(github.ref_name, 'release-') || github.event.pull_request.base.ref == 'master' || startsWith(github.event.pull_request.base.ref, 'release-') }} + steps: + - *checkout + - *install-deps + - *restore-axe-build + - name: Validate Subresource Integrity + run: npm run sri-validate test_node: + # The package can't be built on Node 6 anymore, but should still run there. + # So we need to pull in a previous build artifact. + needs: build strategy: matrix: - node: [6, 18, 20, 22] - runs-on: ubuntu-latest - timeout-minutes: 5 - needs: build + node: + - 6 + - 18 + - 20 + - 22 + - 24 + runs-on: ubuntu-24.04 + timeout-minutes: 10 steps: - - uses: actions/checkout@v5 - - uses: actions/setup-node@v5 - with: - node-version: ${{ matrix.node}} - - uses: actions/download-artifact@v5 + - *checkout + - name: Set up Node.js + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: - name: axe-core - - run: npm run test:node + node-version: ${{ matrix.node }} + - *restore-axe-build + - name: Run Node.js Tests + run: npm run test:node diff --git a/.github/workflows/update-generated-files.yaml b/.github/workflows/update-generated-files.yaml index f10368fa9a..1968e89c50 100644 --- a/.github/workflows/update-generated-files.yaml +++ b/.github/workflows/update-generated-files.yaml @@ -13,10 +13,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version-file: .nvmrc cache: 'npm' diff --git a/.nvmrc b/.nvmrc index 2bd5a0a98a..a45fd52cc5 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22 +24 diff --git a/CHANGELOG.md b/CHANGELOG.md index e1efdf286f..5ecd704fdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ 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.1](https://github.com/dequelabs/axe-core/compare/v4.11.0...v4.11.1) (2026-01-05) + +### Bug Fixes + +- color contrast fails for oklch and oklab with none ([#4959](https://github.com/dequelabs/axe-core/issues/4959)) ([8f249fd](https://github.com/dequelabs/axe-core/commit/8f249fdcffe379466fcff8ec8ac46e37b65fdbce)) +- **commons/color:** Match browser behavior for out-of-gamut oklch colors ([#4908](https://github.com/dequelabs/axe-core/issues/4908)) ([5036be8](https://github.com/dequelabs/axe-core/commit/5036be811e0ede4bf061ab1f970f78b7e9c7ec0c)) +- replaced luminance threshold constant 0.03928 with 0.04045 ([#4934](https://github.com/dequelabs/axe-core/issues/4934)) ([316967d](https://github.com/dequelabs/axe-core/commit/316967d50c554e71bcdf59ac945d1d5bb2f0684b)), closes [#4933](https://github.com/dequelabs/axe-core/issues/4933) +- **rgaa:** adjust mapping of aria-hidden-\* and valid-lang ([#4935](https://github.com/dequelabs/axe-core/issues/4935)) ([77571f2](https://github.com/dequelabs/axe-core/commit/77571f2103a90a5703233729c78be008395f1572)) + ## [4.11.0](https://github.com/dequelabs/axe-core/compare/v4.10.3...v4.11.0) (2025-10-07) ### Features diff --git a/axe.d.ts b/axe.d.ts index 82722edd8c..786b30a233 100644 --- a/axe.d.ts +++ b/axe.d.ts @@ -386,8 +386,10 @@ declare namespace axe { frameContext: FrameContextObject; } - interface RawCheckResult - extends Omit { + interface RawCheckResult extends Omit< + CheckResult, + 'relatedNodes' | 'impact' + > { relatedNodes?: Array; impact?: ImpactValue; } diff --git a/bower.json b/bower.json index 52beb0a4ff..d1d2ba54d0 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "axe-core", - "version": "4.11.0", + "version": "4.11.1", "deprecated": true, "contributors": [ { diff --git a/build/next-version.js b/build/next-version.js deleted file mode 100755 index 189311c0ab..0000000000 --- a/build/next-version.js +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env node - -const fs = require('fs'); -const path = require('path'); -const assert = require('assert'); - -const pkgFile = path.resolve(__dirname, '..', 'package.json'); -const pkg = JSON.parse(fs.readFileSync(pkgFile)); - -const { CIRCLE_SHA1, CIRCLE_BRANCH } = process.env; -assert(CIRCLE_BRANCH, 'CIRCLE_BRANCH environment variable not set'); -assert(CIRCLE_SHA1, 'CIRCLE_SHA1 environment variable not set'); -assert( - CIRCLE_BRANCH === 'develop', - 'This script should only be run from "develop"' -); - -// Shorten the SHA -const GIT_SHA = CIRCLE_SHA1.substr(0, 7); - -// Strip the "dist tag" from the version (if it exists) -const version = pkg.version.replace(/-\w+\.\w+$/, ''); -const nextVersion = `${version}-canary.${GIT_SHA}`; -console.log(nextVersion); diff --git a/doc/developer-guide.md b/doc/developer-guide.md index 0c6b12d3d2..51da6f5ac2 100644 --- a/doc/developer-guide.md +++ b/doc/developer-guide.md @@ -31,7 +31,7 @@ Axe 3.0 supports open Shadow DOM: see our virtual DOM APIs and test utilities fo ### Environment Pre-requisites -1. You must have Node.js version 22 or higher installed. +1. You must have Node.js version 24 or higher installed. If you have [nvm](https://github.com/nvm-sh/nvm) installed, simply do `nvm use` in the root of this repository. 1. Install npm development dependencies. In the root folder of your axe-core repository, run `npm install` diff --git a/doc/projects.md b/doc/projects.md index 8d6da5328c..8b97957a99 100644 --- a/doc/projects.md +++ b/doc/projects.md @@ -61,5 +61,6 @@ Add your project/integration to this file and submit a pull request. 1. [Webatool](https://github.com/balajihambeere/webatool) 1. [A11y Audit Elixir](https://github.com/angelikatyborska/a11y-audit-elixir) 1. [Accented](https://accented.dev) +1. [Happo](https://happo.io) Axe® and axe-core® are registered trademarks of Deque Systems Inc. diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 2341521f30..6858eb6300 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -22,8 +22,8 @@ | [aria-command-name](https://dequeuniversity.com/rules/axe/4.11/aria-command-name?application=RuleDescription) | Ensure every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412, TTv5, TT6.a, EN-301-549, EN-9.4.1.2, ACT, RGAAv4, RGAA-11.9.1 | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1) | | [aria-conditional-attr](https://dequeuniversity.com/rules/axe/4.11/aria-conditional-attr?application=RuleDescription) | Ensure ARIA attributes are used as described in the specification of the element's role | Serious | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure | [5c01ea](https://act-rules.github.io/rules/5c01ea) | | [aria-deprecated-role](https://dequeuniversity.com/rules/axe/4.11/aria-deprecated-role?application=RuleDescription) | Ensure elements do not use deprecated roles | Minor | cat.aria, wcag2a, wcag412, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure | [674b10](https://act-rules.github.io/rules/674b10) | -| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.11/aria-hidden-body?application=RuleDescription) | Ensure aria-hidden="true" is not present on the document body. | Critical | cat.aria, wcag2a, wcag131, wcag412, EN-301-549, EN-9.1.3.1, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure | | -| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.11/aria-hidden-focus?application=RuleDescription) | Ensure aria-hidden elements are not focusable nor contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, TTv5, TT6.a, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-7.1.1 | failure, needs review | [6cfa84](https://act-rules.github.io/rules/6cfa84) | +| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.11/aria-hidden-body?application=RuleDescription) | Ensure aria-hidden="true" is not present on the document body. | Critical | cat.aria, wcag2a, wcag131, wcag412, EN-301-549, EN-9.1.3.1, EN-9.4.1.2, RGAAv4, RGAA-10.8.1 | failure | | +| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.11/aria-hidden-focus?application=RuleDescription) | Ensure aria-hidden elements are not focusable nor contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, TTv5, TT6.a, EN-301-549, EN-9.4.1.2, RGAAv4, RGAA-10.8.1 | failure, needs review | [6cfa84](https://act-rules.github.io/rules/6cfa84) | | [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.11/aria-input-field-name?application=RuleDescription) | Ensure every ARIA input field has an accessible name | Serious | cat.aria, wcag2a, wcag412, TTv5, TT5.c, EN-301-549, EN-9.4.1.2, ACT, RGAAv4, RGAA-11.1.1 | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | | [aria-meter-name](https://dequeuniversity.com/rules/axe/4.11/aria-meter-name?application=RuleDescription) | Ensure every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111, EN-301-549, EN-9.1.1.1, RGAAv4, RGAA-11.1.1 | failure, needs review | | | [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.11/aria-progressbar-name?application=RuleDescription) | Ensure every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111, EN-301-549, EN-9.1.1.1, RGAAv4, RGAA-11.1.1 | failure, needs review | | @@ -73,7 +73,7 @@ | [svg-img-alt](https://dequeuniversity.com/rules/axe/4.11/svg-img-alt?application=RuleDescription) | Ensure <svg> elements with an img, graphics-document or graphics-symbol role have accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, TTv5, TT7.a, EN-301-549, EN-9.1.1.1, ACT, RGAAv4, RGAA-1.1.5 | failure, needs review | [7d6734](https://act-rules.github.io/rules/7d6734) | | [td-headers-attr](https://dequeuniversity.com/rules/axe/4.11/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table that uses the headers attribute refers only to other <th> elements in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g, TTv5, TT14.b, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-5.7.4 | failure, needs review | [a25f45](https://act-rules.github.io/rules/a25f45) | | [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.11/th-has-data-cells?application=RuleDescription) | Ensure that <th> elements and elements with role=columnheader/rowheader have data cells they describe | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g, TTv5, TT14.b, EN-301-549, EN-9.1.3.1, RGAAv4, RGAA-5.7.1 | failure, needs review | [d0f69e](https://act-rules.github.io/rules/d0f69e) | -| [valid-lang](https://dequeuniversity.com/rules/axe/4.11/valid-lang?application=RuleDescription) | Ensure lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312, TTv5, TT11.b, EN-301-549, EN-9.3.1.2, ACT, RGAAv4, RGAA-8.7.1 | failure | [de46e4](https://act-rules.github.io/rules/de46e4) | +| [valid-lang](https://dequeuniversity.com/rules/axe/4.11/valid-lang?application=RuleDescription) | Ensure lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312, TTv5, TT11.b, EN-301-549, EN-9.3.1.2, ACT, RGAAv4, RGAA-8.8.1 | failure | [de46e4](https://act-rules.github.io/rules/de46e4) | | [video-caption](https://dequeuniversity.com/rules/axe/4.11/video-caption?application=RuleDescription) | Ensure <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a, TTv5, TT17.a, EN-301-549, EN-9.1.2.2, RGAAv4, RGAA-4.3.1 | needs review | [eac66b](https://act-rules.github.io/rules/eac66b) | ## WCAG 2.1 Level A & AA Rules diff --git a/eslint.config.js b/eslint.config.js index 203edc2778..495c1d5a23 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -363,6 +363,21 @@ module.exports = [ 'no-use-before-define': 0 } }, + { + files: ['.github/bin/*.mjs'], + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + globals: { + ...globals.node, + ...globals.es2024 + } + }, + rules: { + // Helper scripts for github can import from anywhere + 'no-restricted-imports': ['off'] + } + }, { ignores: [ '**/node_modules/*', diff --git a/lib/checks/color/color-contrast-enhanced.json b/lib/checks/color/color-contrast-enhanced.json index b09a326907..f641840718 100644 --- a/lib/checks/color/color-contrast-enhanced.json +++ b/lib/checks/color/color-contrast-enhanced.json @@ -44,7 +44,8 @@ "equalRatio": "Element has a 1:1 contrast ratio with the background", "shortTextContent": "Element content is too short to determine if it is actual text content", "nonBmp": "Element content contains only non-text characters", - "pseudoContent": "Element's background color could not be determined due to a pseudo element" + "pseudoContent": "Element's background color could not be determined due to a pseudo element", + "colorParse": "Could not parse color string ${data.colorParse}" } } } diff --git a/lib/checks/color/color-contrast-evaluate.js b/lib/checks/color/color-contrast-evaluate.js index 8916bd0971..2319f253c6 100644 --- a/lib/checks/color/color-contrast-evaluate.js +++ b/lib/checks/color/color-contrast-evaluate.js @@ -122,12 +122,24 @@ export default function colorContrastEvaluate(node, options, virtualNode) { // if fgColor or bgColor are missing, get more information. let missing; + let colorParse; + if (bgColor === null) { - missing = incompleteData.get('bgColor'); + if (incompleteData.get('colorParse')) { + missing = 'colorParse'; + colorParse = incompleteData.get('colorParse'); + } else { + missing = incompleteData.get('bgColor'); + } } else if (!isValid) { missing = contrastContributor; } + if (fgColor === null && incompleteData.get('colorParse')) { + missing = 'colorParse'; + colorParse = incompleteData.get('colorParse'); + } + const equalRatio = truncatedResult === 1; const shortTextContent = visibleText.length === 1; if (equalRatio) { @@ -146,7 +158,8 @@ export default function colorContrastEvaluate(node, options, virtualNode) { fontWeight: bold ? 'bold' : 'normal', messageKey: missing, expectedContrastRatio: expected + ':1', - shadowColor: shadowColor ? shadowColor.toHexString() : undefined + shadowColor: shadowColor ? shadowColor.toHexString() : undefined, + colorParse: colorParse }); // We don't know, so we'll put it into Can't Tell diff --git a/lib/checks/color/color-contrast.json b/lib/checks/color/color-contrast.json index 135eeae4e7..6e309208dc 100644 --- a/lib/checks/color/color-contrast.json +++ b/lib/checks/color/color-contrast.json @@ -46,7 +46,8 @@ "equalRatio": "Element has a 1:1 contrast ratio with the background", "shortTextContent": "Element content is too short to determine if it is actual text content", "nonBmp": "Element content contains only non-text characters", - "pseudoContent": "Element's background color could not be determined due to a pseudo element" + "pseudoContent": "Element's background color could not be determined due to a pseudo element", + "colorParse": "Could not parse color string ${data.colorParse}" } } } diff --git a/lib/commons/color/color.js b/lib/commons/color/color.js index 7a5eaa3af6..de8e6ea625 100644 --- a/lib/commons/color/color.js +++ b/lib/commons/color/color.js @@ -1,4 +1,5 @@ import { Colorjs, ArrayFrom } from '../../core/imports'; +import incompleteData from './incomplete-data'; const hexRegex = /^#[0-9a-f]{3,8}$/i; const hslRegex = /hsl\(\s*([-\d.]+)(rad|turn)/; @@ -154,7 +155,12 @@ export default class Color { } // srgb values are between 0 and 1 - const color = new Colorjs(colorString).to('srgb'); + const color = new Colorjs(colorString) + .toGamut({ + space: 'srgb', + method: 'clip' + }) + .to('srgb'); if (prototypeArrayFrom) { Array.from = prototypeArrayFrom; @@ -167,6 +173,7 @@ export default class Color { // color.alpha is a Number object so convert it to a number this.alpha = +color.alpha; } catch { + incompleteData.set('colorParse', colorString); throw new Error(`Unable to parse color "${colorString}"`); } @@ -225,11 +232,11 @@ export default class Color { const { r: rSRGB, g: gSRGB, b: bSRGB } = this; const r = - rSRGB <= 0.03928 ? rSRGB / 12.92 : Math.pow((rSRGB + 0.055) / 1.055, 2.4); + rSRGB <= 0.04045 ? rSRGB / 12.92 : Math.pow((rSRGB + 0.055) / 1.055, 2.4); const g = - gSRGB <= 0.03928 ? gSRGB / 12.92 : Math.pow((gSRGB + 0.055) / 1.055, 2.4); + gSRGB <= 0.04045 ? gSRGB / 12.92 : Math.pow((gSRGB + 0.055) / 1.055, 2.4); const b = - bSRGB <= 0.03928 ? bSRGB / 12.92 : Math.pow((bSRGB + 0.055) / 1.055, 2.4); + bSRGB <= 0.04045 ? bSRGB / 12.92 : Math.pow((bSRGB + 0.055) / 1.055, 2.4); return 0.2126 * r + 0.7152 * g + 0.0722 * b; } diff --git a/lib/commons/color/get-background-color.js b/lib/commons/color/get-background-color.js index 69eb1352a6..136b227505 100644 --- a/lib/commons/color/get-background-color.js +++ b/lib/commons/color/get-background-color.js @@ -75,9 +75,17 @@ function _getBackgroundColor(elm, bgElms, shadowOutlineEmMax) { } // Get the background color - const bgColor = getOwnBackgroundColor(bgElmStyle); - if (bgColor.alpha === 0) { - continue; + let bgColor; + try { + bgColor = getOwnBackgroundColor(bgElmStyle); + if (bgColor.alpha === 0) { + continue; + } + } catch (error) { + if (error && incompleteData.get('colorParse')) { + return null; + } + throw error; } // abort if a node is partially obscured and obscuring element has a background diff --git a/lib/commons/color/get-foreground-color.js b/lib/commons/color/get-foreground-color.js index dca800421e..bc9864c7dd 100644 --- a/lib/commons/color/get-foreground-color.js +++ b/lib/commons/color/get-foreground-color.js @@ -32,17 +32,24 @@ export default function getForegroundColor(node, _, bgColor, options = {}) { ]; let fgColors = []; - for (const colorFn of colorStack) { - const color = colorFn(); - if (!color) { - continue; - } + try { + for (const colorFn of colorStack) { + const color = colorFn(); + if (!color) { + continue; + } - fgColors = fgColors.concat(color); + fgColors = fgColors.concat(color); - if (color.alpha === 1) { - break; + if (color.alpha === 1) { + break; + } + } + } catch (error) { + if (error && incompleteData.get('colorParse')) { + return null; } + throw error; } const fgColor = fgColors.reduce((source, backdrop) => { diff --git a/lib/core/utils/pollyfill-elements-from-point.js b/lib/core/utils/pollyfill-elements-from-point.js index b306f74ad7..43daca54e8 100644 --- a/lib/core/utils/pollyfill-elements-from-point.js +++ b/lib/core/utils/pollyfill-elements-from-point.js @@ -52,7 +52,6 @@ export function pollyfillElementsFromPoint() { for ( i = previousPointerEvents.length; !!(d = previousPointerEvents[--i]); - ) { elements[i].style.setProperty( cssProp, diff --git a/lib/rules/aria-hidden-body.json b/lib/rules/aria-hidden-body.json index 5287cbfe12..513519e62b 100644 --- a/lib/rules/aria-hidden-body.json +++ b/lib/rules/aria-hidden-body.json @@ -13,7 +13,7 @@ "EN-9.1.3.1", "EN-9.4.1.2", "RGAAv4", - "RGAA-7.1.1" + "RGAA-10.8.1" ], "metadata": { "description": "Ensure aria-hidden=\"true\" is not present on the document body.", diff --git a/lib/rules/aria-hidden-focus.json b/lib/rules/aria-hidden-focus.json index 84f3629288..ddd7a93955 100755 --- a/lib/rules/aria-hidden-focus.json +++ b/lib/rules/aria-hidden-focus.json @@ -13,7 +13,7 @@ "EN-301-549", "EN-9.4.1.2", "RGAAv4", - "RGAA-7.1.1" + "RGAA-10.8.1" ], "actIds": ["6cfa84"], "metadata": { diff --git a/lib/rules/valid-lang.json b/lib/rules/valid-lang.json index 0bc56bb445..b8b17ca61c 100644 --- a/lib/rules/valid-lang.json +++ b/lib/rules/valid-lang.json @@ -12,7 +12,7 @@ "EN-9.3.1.2", "ACT", "RGAAv4", - "RGAA-8.7.1" + "RGAA-8.8.1" ], "actIds": ["de46e4"], "metadata": { diff --git a/locales/_template.json b/locales/_template.json index f6239a1f92..d1993f0d82 100644 --- a/locales/_template.json +++ b/locales/_template.json @@ -628,7 +628,8 @@ "equalRatio": "Element has a 1:1 contrast ratio with the background", "shortTextContent": "Element content is too short to determine if it is actual text content", "nonBmp": "Element content contains only non-text characters", - "pseudoContent": "Element's background color could not be determined due to a pseudo element" + "pseudoContent": "Element's background color could not be determined due to a pseudo element", + "colorParse": "Could not parse color string ${data.colorParse}" } }, "color-contrast": { @@ -655,7 +656,8 @@ "equalRatio": "Element has a 1:1 contrast ratio with the background", "shortTextContent": "Element content is too short to determine if it is actual text content", "nonBmp": "Element content contains only non-text characters", - "pseudoContent": "Element's background color could not be determined due to a pseudo element" + "pseudoContent": "Element's background color could not be determined due to a pseudo element", + "colorParse": "Could not parse color string ${data.colorParse}" } }, "link-in-text-block-style": { diff --git a/package-lock.json b/package-lock.json index a9558cd839..ae7ad8e7bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "axe-core", - "version": "4.11.0", + "version": "4.11.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "axe-core", - "version": "4.11.0", + "version": "4.11.1", "license": "MPL-2.0", "devDependencies": { "@axe-core/webdriverjs": "^4.10.2", @@ -18,7 +18,6 @@ "@types/node": "^4.9.5", "aria-practices": "github:w3c/aria-practices#ce0336bd82d7d3651abcbde86af644197ddbc629", "aria-query": "^5.1.3", - "browser-driver-manager": "1.0.4", "chai": "^4.3.7", "chalk": "^4.x", "chromedriver": "*", @@ -93,45 +92,51 @@ "node": ">=0.10.0" } }, + "node_modules/@acemir/cssom": { + "version": "0.9.30", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.30.tgz", + "integrity": "sha512-9CnlMCI0LmCIq0olalQqdWrJHPzm0/tw3gzOA9zJSgvFX7Xau3D24mAGa4BtwxwY69nsuJW6kQqqCzf/mEcQgg==", + "dev": true + }, "node_modules/@asamuzakjp/css-color": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.0.5.tgz", - "integrity": "sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.1.tgz", + "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", "dev": true, "dependencies": { "@csstools/css-calc": "^2.1.4", "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", - "lru-cache": "^11.2.1" + "lru-cache": "^11.2.4" } }, "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", "dev": true, "engines": { "node": "20 || >=22" } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "6.5.7", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.5.7.tgz", - "integrity": "sha512-cvdTPsi2qC1c22UppvuVmx/PDwuc6+QQkwt9OnwQD6Uotbh//tb2XDF0OoK2V0F4b8d02LIwNp3BieaDMAhIhA==", + "version": "6.7.6", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.6.tgz", + "integrity": "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==", "dev": true, "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.2" + "lru-cache": "^11.2.4" } }, "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", "dev": true, "engines": { "node": "20 || >=22" @@ -144,12 +149,12 @@ "dev": true }, "node_modules/@axe-core/webdriverjs": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/@axe-core/webdriverjs/-/webdriverjs-4.10.2.tgz", - "integrity": "sha512-ppnc7+xG4KEQ0cnKOOB7B4+ACrB13O0BPVhzJpDSQ1LlBNrWdMlfdJujMhnE0v6gsOV0YxnbZQnokaGOaaFIjQ==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@axe-core/webdriverjs/-/webdriverjs-4.11.0.tgz", + "integrity": "sha512-Qt9DWcCQIPU9TMfCQnibFn0JDuvoSzfGs4nZM7LJeae/i3bpZ5qqLjc94U09BUneYQjTicfwHlKTcr9mmAb2cg==", "dev": true, "dependencies": { - "axe-core": "~4.10.3" + "axe-core": "~4.11.0" }, "peerDependencies": { "selenium-webdriver": ">3.0.0-beta || >=2.53.1 || >4.0.0-alpha" @@ -171,29 +176,29 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", - "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -210,13 +215,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "dev": true, "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -485,11 +490,10 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -533,12 +537,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "dev": true, "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -548,14 +552,13 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", - "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -789,9 +792,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", - "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -837,9 +840,9 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.3.tgz", - "integrity": "sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -847,7 +850,7 @@ "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/traverse": "^7.28.4" }, "engines": { "node": ">=6.9.0" @@ -874,13 +877,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", - "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -972,11 +975,10 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", - "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", + "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1071,11 +1073,10 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1137,16 +1138,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", + "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1238,16 +1238,16 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", - "integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.4" }, "engines": { "node": ">=6.9.0" @@ -1290,11 +1290,10 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" @@ -1373,9 +1372,9 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.3.tgz", - "integrity": "sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1569,16 +1568,16 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz", - "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", + "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.28.0", + "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", @@ -1591,42 +1590,42 @@ "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.0", + "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.3", + "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", @@ -1694,17 +1693,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/types": "^7.28.5", "debug": "^4.3.1" }, "engines": { @@ -1712,22 +1711,22 @@ } }, "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@bazel/runfiles": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@bazel/runfiles/-/runfiles-6.3.1.tgz", - "integrity": "sha512-1uLNT5NZsUVIGS4syuHwTzZ8HycMPyr6POA3FCE4GbMtc4rhoJk8aZKtNIRthJYfL+iioppi+rTfH3olMPr9nA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@bazel/runfiles/-/runfiles-6.5.0.tgz", + "integrity": "sha512-RzahvqTkfpY2jsDxo8YItPX+/iZ6hbiikw1YhE0bA9EKBR5Og8Pa6FHn9PO9M0zaXRVsr0GFQLKbB/0rzy9SzA==", "dev": true }, "node_modules/@colors/colors": { @@ -1831,9 +1830,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.14.tgz", - "integrity": "sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==", + "version": "1.0.22", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.22.tgz", + "integrity": "sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw==", "dev": true, "funding": [ { @@ -1847,9 +1846,6 @@ ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" } }, "node_modules/@csstools/css-tokenizer": { @@ -1911,12 +1907,12 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", "dev": true, "dependencies": { - "@eslint/object-schema": "^2.1.6", + "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -1925,18 +1921,21 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", - "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, + "dependencies": { + "@eslint/core": "^0.17.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/core": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", - "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.15" @@ -1983,9 +1982,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", - "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1995,21 +1994,21 @@ } }, "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", - "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "dependencies": { - "@eslint/core": "^0.15.2", + "@eslint/core": "^0.17.0", "levn": "^0.4.1" }, "engines": { @@ -2047,9 +2046,9 @@ "dev": true }, "node_modules/@hapi/tlds": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.3.tgz", - "integrity": "sha512-QIvUMB5VZ8HMLZF9A2oWr3AFM430QC8oGd0L35y2jHpuW6bIIca6x/xL7zUf4J7L9WJ3qjz+iJII8ncaeMbpSg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.4.tgz", + "integrity": "sha512-Fq+20dxsxLaUn5jSSWrdtSRcIUba2JquuorF9UW1wIJS5cSUwxIsO2GIhaWynPRflvxSzFN+gxKte2HEW1OuoA==", "dev": true, "engines": { "node": ">=14.0.0" @@ -2427,23 +2426,21 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", - "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "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==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "node_modules/@sinonjs/samsam": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", - "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", + "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.1", - "lodash.get": "^4.4.2", "type-detect": "^4.1.0" } }, @@ -2787,28 +2784,19 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/axe-core": { - "version": "4.10.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz", - "integrity": "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.0.tgz", + "integrity": "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/axios": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "dev": true, "dependencies": { "follow-redirects": "^1.15.6", @@ -3070,49 +3058,6 @@ "node": ">=8" } }, - "node_modules/browser-driver-manager": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/browser-driver-manager/-/browser-driver-manager-1.0.4.tgz", - "integrity": "sha512-Ilh4sNgqZYJ9KL2KHg6xCE3A/pWPDVpzhC/0dBuoYCbrPRMIaG3S2YroWU2swjltagosz3ldSVIgZbrlgUpysA==", - "dev": true, - "dependencies": { - "chalk": "^5.0.0", - "node-fetch": "^3.2.0" - }, - "bin": { - "browser-driver-manager": "bin/browser-driver-manager" - } - }, - "node_modules/browser-driver-manager/node_modules/chalk": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz", - "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==", - "dev": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/browser-driver-manager/node_modules/node-fetch": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", - "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", - "dev": true, - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -3428,14 +3373,14 @@ } }, "node_modules/chromedriver": { - "version": "138.0.5", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-138.0.5.tgz", - "integrity": "sha512-WE5O09if9TmFfIpvydt5dyhj+TNTUttvnujoRtAShQuDghulSh1HFirBnjNrAWjEoMkXn9VUw+cCYzZ597VPJQ==", + "version": "142.0.3", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-142.0.3.tgz", + "integrity": "sha512-1Ibm/tuJRTaIpRfGi6M3IEb61CAlPirkFHvfiLiiu3h8OEtJFKat/FSr8Rn8pBsJlCCRlb5UWdj+nZeAmRLQUg==", "dev": true, "hasInstallScript": true, "dependencies": { "@testim/chrome-version": "^1.1.4", - "axios": "^1.7.4", + "axios": "^1.12.0", "compare-versions": "^6.1.0", "extract-zip": "^2.0.1", "proxy-agent": "^6.4.0", @@ -3562,9 +3507,9 @@ } }, "node_modules/cli-truncate": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.0.tgz", - "integrity": "sha512-7JDGG+4Zp0CsknDCedl0DYdaeOhc46QNpXi3NLQblkZpXXgA6LncLDUUyvrjSvZeF3VRQa+KiMGomazQrC1V8g==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", + "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", "dev": true, "dependencies": { "slice-ansi": "^7.1.0", @@ -3730,9 +3675,9 @@ } }, "node_modules/commander": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", - "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", "dev": true, "engines": { "node": ">=20" @@ -4289,9 +4234,9 @@ } }, "node_modules/core-js": { - "version": "3.45.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz", - "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==", + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz", + "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", "dev": true, "hasInstallScript": true, "funding": { @@ -4413,19 +4358,29 @@ } }, "node_modules/cssstyle": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.1.tgz", - "integrity": "sha512-g5PC9Aiph9eiczFpcgUhd9S4UUO3F+LHGRIi5NUMZ+4xtoIYbHNZwZnWA2JsFGe8OU8nl4WyaEFiZuGuxlutJQ==", + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.6.tgz", + "integrity": "sha512-legscpSpgSAeGEe0TNcai97DKt9Vd9AsAdOL7Uoetb52Ar/8eJm3LIa39qpv8wWzLFlNG4vVvppQM+teaMPj3A==", "dev": true, "dependencies": { - "@asamuzakjp/css-color": "^4.0.3", - "@csstools/css-syntax-patches-for-csstree": "^1.0.14", - "css-tree": "^3.1.0" + "@asamuzakjp/css-color": "^4.1.1", + "@csstools/css-syntax-patches-for-csstree": "^1.0.21", + "css-tree": "^3.1.0", + "lru-cache": "^11.2.4" }, "engines": { "node": ">=20" } }, + "node_modules/cssstyle/node_modules/lru-cache": { + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "dev": true, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -4454,15 +4409,6 @@ "node": ">=8" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", - "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, "node_modules/data-urls": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", @@ -4546,11 +4492,10 @@ } }, "node_modules/decimal.js": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", - "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", - "dev": true, - "license": "MIT" + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true }, "node_modules/deep-eql": { "version": "4.1.3", @@ -4935,9 +4880,9 @@ "dev": true }, "node_modules/emoji-regex": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", - "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true }, "node_modules/encodeurl": { @@ -5287,24 +5232,23 @@ } }, "node_modules/eslint": { - "version": "9.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", - "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.3.1", - "@eslint/core": "^0.15.2", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.36.0", - "@eslint/plugin-kit": "^0.3.5", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", @@ -5696,29 +5640,6 @@ "pend": "~1.2.0" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -6002,18 +5923,6 @@ "node": ">= 6" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dev": true, - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", @@ -6369,9 +6278,9 @@ } }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", @@ -6467,9 +6376,9 @@ } }, "node_modules/globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true, "engines": { "node": ">=18" @@ -7725,6 +7634,15 @@ "node": ">=8" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -7972,9 +7890,9 @@ } }, "node_modules/joi": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-18.0.1.tgz", - "integrity": "sha512-IiQpRyypSnLisQf3PwuN2eIHAsAIGZIrLZkd4zdvIar2bDyhM91ubRjy8a3eYablXsh9BeI/c7dmPYHca5qtoA==", + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/joi/-/joi-18.0.2.tgz", + "integrity": "sha512-RuCOQMIt78LWnktPoeBL0GErkNaJPTBGcYuyaBvUOQSpcpcLfWrHPPihYdOGbV5pam9VTWbeoF7TsGiHugcjGA==", "dev": true, "dependencies": { "@hapi/address": "^5.1.1", @@ -8029,9 +7947,9 @@ "dev": true }, "node_modules/jsdoc": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz", - "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.5.tgz", + "integrity": "sha512-P4C6MWP9yIlMiK8nwoZvxN84vb6MsnXcHuy7XzVOvQoCizWX5JFCBsWIIWKXBltpoRZXddUOVQmCTOZt9yDj9g==", "dev": true, "dependencies": { "@babel/parser": "^7.20.15", @@ -8067,21 +7985,21 @@ } }, "node_modules/jsdom": { - "version": "27.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.0.0.tgz", - "integrity": "sha512-lIHeR1qlIRrIN5VMccd8tI2Sgw6ieYXSVktcSHaNe3Z5nE/tcPQYQWOq00wxMvYOsz+73eAkNenVvmPC6bba9A==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.3.0.tgz", + "integrity": "sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==", "dev": true, "dependencies": { - "@asamuzakjp/dom-selector": "^6.5.4", - "cssstyle": "^5.3.0", + "@acemir/cssom": "^0.9.28", + "@asamuzakjp/dom-selector": "^6.7.6", + "cssstyle": "^5.3.4", "data-urls": "^6.0.0", - "decimal.js": "^10.5.0", + "decimal.js": "^10.6.0", "html-encoding-sniffer": "^4.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", - "parse5": "^7.3.0", - "rrweb-cssom": "^0.8.0", + "parse5": "^8.0.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.0", @@ -8089,12 +8007,12 @@ "webidl-conversions": "^8.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.0.0", - "ws": "^8.18.2", + "whatwg-url": "^15.1.0", + "ws": "^8.18.3", "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=20" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { "canvas": "^3.0.0" @@ -8612,18 +8530,18 @@ } }, "node_modules/lint-staged": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.0.tgz", - "integrity": "sha512-spdYSOCQ2MdZ9CM1/bu/kDmaYGsrpNOeu1InFFV8uhv14x6YIubGxbCpSmGILFoxkiheNQPDXSg5Sbb5ZuVnug==", + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", + "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", "dev": true, "dependencies": { - "commander": "14.0.1", - "listr2": "9.0.4", - "micromatch": "4.0.8", - "nano-spawn": "1.0.3", - "pidtree": "0.6.0", - "string-argv": "0.3.2", - "yaml": "2.8.1" + "commander": "^14.0.2", + "listr2": "^9.0.5", + "micromatch": "^4.0.8", + "nano-spawn": "^2.0.0", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.1" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -8636,9 +8554,9 @@ } }, "node_modules/listr2": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.4.tgz", - "integrity": "sha512-1wd/kpAdKRLwv7/3OKC8zZ5U8e/fajCfWMxacUvB79S5nLrYGPtUI/8chMQhn3LQjsRVErTb9i1ECAwW0ZIHnQ==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", "dev": true, "dependencies": { "cli-truncate": "^5.0.0", @@ -8788,12 +8706,6 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, "node_modules/lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", @@ -9384,9 +9296,9 @@ } }, "node_modules/mocha": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.2.tgz", - "integrity": "sha512-lkqVJPmqqG/w5jmmFtiRvtA2jkDyNVUcefFJKb2uyX4dekk8Okgqop3cgbFiaIvj8uCRJVTP5x9dfxGyXm2jvQ==", + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", "dev": true, "dependencies": { "browser-stdout": "^1.3.1", @@ -9397,6 +9309,7 @@ "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", "minimatch": "^9.0.5", @@ -9593,9 +9506,9 @@ "dev": true }, "node_modules/nano-spawn": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-1.0.3.tgz", - "integrity": "sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA==", + "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" @@ -9604,25 +9517,6 @@ "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" } }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -9675,25 +9569,6 @@ "tslib": "^2.0.3" } }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, "node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -10394,9 +10269,9 @@ } }, "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", + "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", "dev": true, "dependencies": { "entities": "^6.0.0" @@ -10437,9 +10312,9 @@ } }, "node_modules/patch-package": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz", - "integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz", + "integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==", "dev": true, "dependencies": { "@yarnpkg/lockfile": "^1.1.0", @@ -10447,15 +10322,14 @@ "ci-info": "^3.7.0", "cross-spawn": "^7.0.3", "find-yarn-workspace-root": "^2.0.0", - "fs-extra": "^9.0.0", + "fs-extra": "^10.0.0", "json-stable-stringify": "^1.0.2", "klaw-sync": "^6.0.0", "minimist": "^1.2.6", "open": "^7.4.2", - "rimraf": "^2.6.3", "semver": "^7.5.3", "slash": "^2.0.0", - "tmp": "^0.0.33", + "tmp": "^0.2.4", "yaml": "^2.2.2" }, "bin": { @@ -10467,44 +10341,23 @@ } }, "node_modules/patch-package/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/patch-package/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=12" } }, "node_modules/patch-package/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "dependencies": { "universalify": "^2.0.0" @@ -10513,18 +10366,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/patch-package/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/patch-package/node_modules/semver": { "version": "7.6.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", @@ -10537,18 +10378,6 @@ "node": ">=10" } }, - "node_modules/patch-package/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/patch-package/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -10756,35 +10585,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -10795,9 +10595,9 @@ } }, "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -11496,12 +11296,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", - "dev": true - }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -11572,9 +11366,9 @@ "dev": true }, "node_modules/selenium-webdriver": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.35.0.tgz", - "integrity": "sha512-Baaeiuyu7BIIsSYf0SI7Mi55gsNmdI00KM0Hcofw1RnAY+0QEVpdh5yAxueDxgTZS8vcbGZFU0NJ6Qc1riIrLg==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.39.0.tgz", + "integrity": "sha512-NAs9jCU+UeZ/ZmRb8R6zOp7N8eMklefdBYASnaRmCNXdgFE8w3OCxxZmLixkwqnGDHY5VF7hCulfw1Mls43N/A==", "dev": true, "funding": [ { @@ -11587,10 +11381,10 @@ } ], "dependencies": { - "@bazel/runfiles": "^6.3.1", + "@bazel/runfiles": "^6.5.0", "jszip": "^3.10.1", - "tmp": "^0.2.3", - "ws": "^8.18.2" + "tmp": "^0.2.5", + "ws": "^8.18.3" }, "engines": { "node": ">= 20.0.0" @@ -11779,15 +11573,15 @@ "dev": true }, "node_modules/sinon": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.0.tgz", - "integrity": "sha512-TOgRcwFPbfGtpqvZw+hyqJDvqfapr1qUlOizROIk4bBLjlsjlB00Pg6wMFXNtJRpu+eCZuVOaLatG7M8105kAw==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.1.tgz", + "integrity": "sha512-Z0NVCW45W8Mg5oC/27/+fCqIHFnW8kpkFOq0j9XJIev4Ld0mKmERaZv5DMLAb9fGCevjKwaEeIQz5+MBXfZcDw==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^13.0.5", - "@sinonjs/samsam": "^8.0.1", - "diff": "^7.0.0", + "@sinonjs/fake-timers": "^15.1.0", + "@sinonjs/samsam": "^8.0.3", + "diff": "^8.0.2", "supports-color": "^7.2.0" }, "funding": { @@ -11795,6 +11589,15 @@ "url": "https://opencollective.com/sinon" } }, + "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==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -12166,9 +11969,9 @@ } }, "node_modules/start-server-and-test": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.1.2.tgz", - "integrity": "sha512-OIjfo3G6QV9Sh6IlMqj58oZwVhPVuU/l6uVACG7YNE9kAfDvcYoPThtb0NNT3tZMMC3wOYbXnC15yiCSNFkdRg==", + "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==", "dev": true, "dependencies": { "arg": "^5.0.2", @@ -12178,7 +11981,7 @@ "execa": "5.1.1", "lazy-ass": "1.6.0", "ps-tree": "1.2.0", - "wait-on": "8.0.5" + "wait-on": "9.0.3" }, "bin": { "server-test": "src/bin/start.js", @@ -12641,9 +12444,9 @@ "dev": true }, "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "dev": true, "engines": { "node": ">=14.14" @@ -12771,9 +12574,9 @@ } }, "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -13077,12 +12880,12 @@ } }, "node_modules/wait-on": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-8.0.5.tgz", - "integrity": "sha512-J3WlS0txVHkhLRb2FsmRg3dkMTCV1+M6Xra3Ho7HzZDHpE7DCOnoSoCJsZotrmW3uRMhvIJGSKUKrh/MeF4iag==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-9.0.3.tgz", + "integrity": "sha512-13zBnyYvFDW1rBvWiJ6Av3ymAaq8EDQuvxZnPIw3g04UqGi4TyoIJABmfJ6zrvKo9yeFQExNkOk7idQbDJcuKA==", "dev": true, "dependencies": { - "axios": "^1.12.1", + "axios": "^1.13.2", "joi": "^18.0.1", "lodash": "^4.17.21", "minimist": "^1.2.8", @@ -13092,7 +12895,7 @@ "wait-on": "bin/wait-on" }, "engines": { - "node": ">=12.0.0" + "node": ">=20.0.0" } }, "node_modules/wcag-act-rules": { @@ -13119,15 +12922,6 @@ "node": ">=8.10.0" } }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/webidl-conversions": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.0.tgz", @@ -13560,44 +13354,50 @@ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true }, + "@acemir/cssom": { + "version": "0.9.30", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.30.tgz", + "integrity": "sha512-9CnlMCI0LmCIq0olalQqdWrJHPzm0/tw3gzOA9zJSgvFX7Xau3D24mAGa4BtwxwY69nsuJW6kQqqCzf/mEcQgg==", + "dev": true + }, "@asamuzakjp/css-color": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.0.5.tgz", - "integrity": "sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.1.tgz", + "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", "dev": true, "requires": { "@csstools/css-calc": "^2.1.4", "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", - "lru-cache": "^11.2.1" + "lru-cache": "^11.2.4" }, "dependencies": { "lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", "dev": true } } }, "@asamuzakjp/dom-selector": { - "version": "6.5.7", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.5.7.tgz", - "integrity": "sha512-cvdTPsi2qC1c22UppvuVmx/PDwuc6+QQkwt9OnwQD6Uotbh//tb2XDF0OoK2V0F4b8d02LIwNp3BieaDMAhIhA==", + "version": "6.7.6", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.6.tgz", + "integrity": "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==", "dev": true, "requires": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.2" + "lru-cache": "^11.2.4" }, "dependencies": { "lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", "dev": true } } @@ -13609,12 +13409,12 @@ "dev": true }, "@axe-core/webdriverjs": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/@axe-core/webdriverjs/-/webdriverjs-4.10.2.tgz", - "integrity": "sha512-ppnc7+xG4KEQ0cnKOOB7B4+ACrB13O0BPVhzJpDSQ1LlBNrWdMlfdJujMhnE0v6gsOV0YxnbZQnokaGOaaFIjQ==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@axe-core/webdriverjs/-/webdriverjs-4.11.0.tgz", + "integrity": "sha512-Qt9DWcCQIPU9TMfCQnibFn0JDuvoSzfGs4nZM7LJeae/i3bpZ5qqLjc94U09BUneYQjTicfwHlKTcr9mmAb2cg==", "dev": true, "requires": { - "axe-core": "~4.10.3" + "axe-core": "~4.11.0" } }, "@babel/code-frame": { @@ -13629,26 +13429,26 @@ } }, "@babel/compat-data": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", - "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "dev": true }, "@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "requires": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -13658,13 +13458,13 @@ } }, "@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "dev": true, "requires": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -13856,9 +13656,9 @@ "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true }, "@babel/helper-validator-option": { @@ -13889,22 +13689,22 @@ } }, "@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "dev": true, "requires": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.5" } }, "@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", - "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.5" } }, "@babel/plugin-bugfix-safari-class-field-initializer-scope": { @@ -14044,9 +13844,9 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", - "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.27.1" @@ -14073,9 +13873,9 @@ } }, "@babel/plugin-transform-classes": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.3.tgz", - "integrity": "sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -14083,7 +13883,7 @@ "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/traverse": "^7.28.4" } }, "@babel/plugin-transform-computed-properties": { @@ -14097,13 +13897,13 @@ } }, "@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", - "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.5" } }, "@babel/plugin-transform-dotall-regex": { @@ -14155,9 +13955,9 @@ } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", - "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", + "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.27.1" @@ -14212,9 +14012,9 @@ } }, "@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.27.1" @@ -14250,15 +14050,15 @@ } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", + "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" } }, "@babel/plugin-transform-modules-umd": { @@ -14309,16 +14109,16 @@ } }, "@babel/plugin-transform-object-rest-spread": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", - "integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", "dev": true, "requires": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.4" } }, "@babel/plugin-transform-object-super": { @@ -14341,9 +14141,9 @@ } }, "@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.27.1", @@ -14390,9 +14190,9 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.3.tgz", - "integrity": "sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.27.1" @@ -14503,16 +14303,16 @@ } }, "@babel/preset-env": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz", - "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", + "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", "dev": true, "requires": { - "@babel/compat-data": "^7.28.0", + "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", @@ -14525,42 +14325,42 @@ "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.0", + "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.3", + "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", @@ -14612,34 +14412,34 @@ } }, "@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "dev": true, "requires": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" } }, "@bazel/runfiles": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@bazel/runfiles/-/runfiles-6.3.1.tgz", - "integrity": "sha512-1uLNT5NZsUVIGS4syuHwTzZ8HycMPyr6POA3FCE4GbMtc4rhoJk8aZKtNIRthJYfL+iioppi+rTfH3olMPr9nA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@bazel/runfiles/-/runfiles-6.5.0.tgz", + "integrity": "sha512-RzahvqTkfpY2jsDxo8YItPX+/iZ6hbiikw1YhE0bA9EKBR5Og8Pa6FHn9PO9M0zaXRVsr0GFQLKbB/0rzy9SzA==", "dev": true }, "@colors/colors": { @@ -14679,11 +14479,10 @@ "requires": {} }, "@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.14.tgz", - "integrity": "sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==", - "dev": true, - "requires": {} + "version": "1.0.22", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.22.tgz", + "integrity": "sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw==", + "dev": true }, "@csstools/css-tokenizer": { "version": "3.0.4", @@ -14713,26 +14512,29 @@ "dev": true }, "@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", "dev": true, "requires": { - "@eslint/object-schema": "^2.1.6", + "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "@eslint/config-helpers": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", - "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", - "dev": true + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "requires": { + "@eslint/core": "^0.17.0" + } }, "@eslint/core": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", - "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.15" @@ -14764,24 +14566,24 @@ } }, "@eslint/js": { - "version": "9.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", - "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true }, "@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true }, "@eslint/plugin-kit": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", - "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "requires": { - "@eslint/core": "^0.15.2", + "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, @@ -14813,9 +14615,9 @@ "dev": true }, "@hapi/tlds": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.3.tgz", - "integrity": "sha512-QIvUMB5VZ8HMLZF9A2oWr3AFM430QC8oGd0L35y2jHpuW6bIIca6x/xL7zUf4J7L9WJ3qjz+iJII8ncaeMbpSg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.4.tgz", + "integrity": "sha512-Fq+20dxsxLaUn5jSSWrdtSRcIUba2JquuorF9UW1wIJS5cSUwxIsO2GIhaWynPRflvxSzFN+gxKte2HEW1OuoA==", "dev": true }, "@hapi/topo": { @@ -15119,22 +14921,21 @@ } }, "@sinonjs/fake-timers": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", - "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "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==", "dev": true, "requires": { "@sinonjs/commons": "^3.0.1" } }, "@sinonjs/samsam": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", - "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", + "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", "dev": true, "requires": { "@sinonjs/commons": "^3.0.1", - "lodash.get": "^4.4.2", "type-detect": "^4.1.0" }, "dependencies": { @@ -15420,22 +15221,16 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, "axe-core": { - "version": "4.10.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz", - "integrity": "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.0.tgz", + "integrity": "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==", "dev": true }, "axios": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "dev": true, "requires": { "follow-redirects": "^1.15.6", @@ -15655,35 +15450,6 @@ "fill-range": "^7.1.1" } }, - "browser-driver-manager": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/browser-driver-manager/-/browser-driver-manager-1.0.4.tgz", - "integrity": "sha512-Ilh4sNgqZYJ9KL2KHg6xCE3A/pWPDVpzhC/0dBuoYCbrPRMIaG3S2YroWU2swjltagosz3ldSVIgZbrlgUpysA==", - "dev": true, - "requires": { - "chalk": "^5.0.0", - "node-fetch": "^3.2.0" - }, - "dependencies": { - "chalk": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.1.2.tgz", - "integrity": "sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==", - "dev": true - }, - "node-fetch": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", - "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", - "dev": true, - "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - } - } - } - }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -15892,13 +15658,13 @@ } }, "chromedriver": { - "version": "138.0.5", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-138.0.5.tgz", - "integrity": "sha512-WE5O09if9TmFfIpvydt5dyhj+TNTUttvnujoRtAShQuDghulSh1HFirBnjNrAWjEoMkXn9VUw+cCYzZ597VPJQ==", + "version": "142.0.3", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-142.0.3.tgz", + "integrity": "sha512-1Ibm/tuJRTaIpRfGi6M3IEb61CAlPirkFHvfiLiiu3h8OEtJFKat/FSr8Rn8pBsJlCCRlb5UWdj+nZeAmRLQUg==", "dev": true, "requires": { "@testim/chrome-version": "^1.1.4", - "axios": "^1.7.4", + "axios": "^1.12.0", "compare-versions": "^6.1.0", "extract-zip": "^2.0.1", "proxy-agent": "^6.4.0", @@ -15988,9 +15754,9 @@ "dev": true }, "cli-truncate": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.0.tgz", - "integrity": "sha512-7JDGG+4Zp0CsknDCedl0DYdaeOhc46QNpXi3NLQblkZpXXgA6LncLDUUyvrjSvZeF3VRQa+KiMGomazQrC1V8g==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", + "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", "dev": true, "requires": { "slice-ansi": "^7.1.0", @@ -16115,9 +15881,9 @@ } }, "commander": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", - "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", "dev": true }, "compare-func": { @@ -16555,9 +16321,9 @@ "dev": true }, "core-js": { - "version": "3.45.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz", - "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==", + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz", + "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", "dev": true }, "core-js-compat": { @@ -16644,14 +16410,23 @@ "dev": true }, "cssstyle": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.1.tgz", - "integrity": "sha512-g5PC9Aiph9eiczFpcgUhd9S4UUO3F+LHGRIi5NUMZ+4xtoIYbHNZwZnWA2JsFGe8OU8nl4WyaEFiZuGuxlutJQ==", + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.6.tgz", + "integrity": "sha512-legscpSpgSAeGEe0TNcai97DKt9Vd9AsAdOL7Uoetb52Ar/8eJm3LIa39qpv8wWzLFlNG4vVvppQM+teaMPj3A==", "dev": true, "requires": { - "@asamuzakjp/css-color": "^4.0.3", - "@csstools/css-syntax-patches-for-csstree": "^1.0.14", - "css-tree": "^3.1.0" + "@asamuzakjp/css-color": "^4.1.1", + "@csstools/css-syntax-patches-for-csstree": "^1.0.21", + "css-tree": "^3.1.0", + "lru-cache": "^11.2.4" + }, + "dependencies": { + "lru-cache": { + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "dev": true + } } }, "custom-event": { @@ -16676,12 +16451,6 @@ "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", "dev": true }, - "data-uri-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", - "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", - "dev": true - }, "data-urls": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", @@ -16738,9 +16507,9 @@ } }, "decimal.js": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", - "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", "dev": true }, "deep-eql": { @@ -17032,9 +16801,9 @@ "dev": true }, "emoji-regex": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", - "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true }, "encodeurl": { @@ -17303,24 +17072,23 @@ } }, "eslint": { - "version": "9.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", - "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.3.1", - "@eslint/core": "^0.15.2", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.36.0", - "@eslint/plugin-kit": "^0.3.5", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", @@ -17606,16 +17374,6 @@ "pend": "~1.2.0" } }, - "fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "dev": true, - "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - } - }, "figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -17827,15 +17585,6 @@ "mime-types": "^2.1.12" } }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dev": true, - "requires": { - "fetch-blob": "^3.1.2" - } - }, "from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", @@ -18095,9 +17844,9 @@ } }, "glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "requires": { "foreground-child": "^3.1.0", @@ -18173,9 +17922,9 @@ } }, "globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true }, "globule": { @@ -19076,6 +18825,12 @@ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -19246,9 +19001,9 @@ } }, "joi": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-18.0.1.tgz", - "integrity": "sha512-IiQpRyypSnLisQf3PwuN2eIHAsAIGZIrLZkd4zdvIar2bDyhM91ubRjy8a3eYablXsh9BeI/c7dmPYHca5qtoA==", + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/joi/-/joi-18.0.2.tgz", + "integrity": "sha512-RuCOQMIt78LWnktPoeBL0GErkNaJPTBGcYuyaBvUOQSpcpcLfWrHPPihYdOGbV5pam9VTWbeoF7TsGiHugcjGA==", "dev": true, "requires": { "@hapi/address": "^5.1.1", @@ -19297,9 +19052,9 @@ "dev": true }, "jsdoc": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz", - "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.5.tgz", + "integrity": "sha512-P4C6MWP9yIlMiK8nwoZvxN84vb6MsnXcHuy7XzVOvQoCizWX5JFCBsWIIWKXBltpoRZXddUOVQmCTOZt9yDj9g==", "dev": true, "requires": { "@babel/parser": "^7.20.15", @@ -19328,21 +19083,21 @@ } }, "jsdom": { - "version": "27.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.0.0.tgz", - "integrity": "sha512-lIHeR1qlIRrIN5VMccd8tI2Sgw6ieYXSVktcSHaNe3Z5nE/tcPQYQWOq00wxMvYOsz+73eAkNenVvmPC6bba9A==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.3.0.tgz", + "integrity": "sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==", "dev": true, "requires": { - "@asamuzakjp/dom-selector": "^6.5.4", - "cssstyle": "^5.3.0", + "@acemir/cssom": "^0.9.28", + "@asamuzakjp/dom-selector": "^6.7.6", + "cssstyle": "^5.3.4", "data-urls": "^6.0.0", - "decimal.js": "^10.5.0", + "decimal.js": "^10.6.0", "html-encoding-sniffer": "^4.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", - "parse5": "^7.3.0", - "rrweb-cssom": "^0.8.0", + "parse5": "^8.0.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.0", @@ -19350,8 +19105,8 @@ "webidl-conversions": "^8.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.0.0", - "ws": "^8.18.2", + "whatwg-url": "^15.1.0", + "ws": "^8.18.3", "xml-name-validator": "^5.0.0" }, "dependencies": { @@ -19767,24 +19522,24 @@ } }, "lint-staged": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.0.tgz", - "integrity": "sha512-spdYSOCQ2MdZ9CM1/bu/kDmaYGsrpNOeu1InFFV8uhv14x6YIubGxbCpSmGILFoxkiheNQPDXSg5Sbb5ZuVnug==", + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", + "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", "dev": true, "requires": { - "commander": "14.0.1", - "listr2": "9.0.4", - "micromatch": "4.0.8", - "nano-spawn": "1.0.3", - "pidtree": "0.6.0", - "string-argv": "0.3.2", - "yaml": "2.8.1" + "commander": "^14.0.2", + "listr2": "^9.0.5", + "micromatch": "^4.0.8", + "nano-spawn": "^2.0.0", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.1" } }, "listr2": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.4.tgz", - "integrity": "sha512-1wd/kpAdKRLwv7/3OKC8zZ5U8e/fajCfWMxacUvB79S5nLrYGPtUI/8chMQhn3LQjsRVErTb9i1ECAwW0ZIHnQ==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", "dev": true, "requires": { "cli-truncate": "^5.0.0", @@ -19893,12 +19648,6 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, "lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", @@ -20312,9 +20061,9 @@ "dev": true }, "mocha": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.2.tgz", - "integrity": "sha512-lkqVJPmqqG/w5jmmFtiRvtA2jkDyNVUcefFJKb2uyX4dekk8Okgqop3cgbFiaIvj8uCRJVTP5x9dfxGyXm2jvQ==", + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", "dev": true, "requires": { "browser-stdout": "^1.3.1", @@ -20325,6 +20074,7 @@ "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", "minimatch": "^9.0.5", @@ -20463,18 +20213,11 @@ "dev": true }, "nano-spawn": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-1.0.3.tgz", - "integrity": "sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", + "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", "dev": true }, - "nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "peer": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -20521,12 +20264,6 @@ "tslib": "^2.0.3" } }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "dev": true - }, "node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -21059,9 +20796,9 @@ "dev": true }, "parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", + "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", "dev": true, "requires": { "entities": "^6.0.0" @@ -21092,9 +20829,9 @@ } }, "patch-package": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz", - "integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz", + "integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==", "dev": true, "requires": { "@yarnpkg/lockfile": "^1.1.0", @@ -21102,78 +20839,44 @@ "ci-info": "^3.7.0", "cross-spawn": "^7.0.3", "find-yarn-workspace-root": "^2.0.0", - "fs-extra": "^9.0.0", + "fs-extra": "^10.0.0", "json-stable-stringify": "^1.0.2", "klaw-sync": "^6.0.0", "minimist": "^1.2.6", "open": "^7.4.2", - "rimraf": "^2.6.3", "semver": "^7.5.3", "slash": "^2.0.0", - "tmp": "^0.0.33", + "tmp": "^0.2.4", "yaml": "^2.2.2" }, "dependencies": { "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "requires": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" } }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, "semver": { "version": "7.6.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, "universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -21336,18 +21039,6 @@ } } }, - "postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "peer": true, - "requires": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - } - }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -21355,9 +21046,9 @@ "dev": true }, "prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", "dev": true }, "pretty-bytes": { @@ -21884,12 +21575,6 @@ } } }, - "rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", - "dev": true - }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -21950,15 +21635,15 @@ "dev": true }, "selenium-webdriver": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.35.0.tgz", - "integrity": "sha512-Baaeiuyu7BIIsSYf0SI7Mi55gsNmdI00KM0Hcofw1RnAY+0QEVpdh5yAxueDxgTZS8vcbGZFU0NJ6Qc1riIrLg==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.39.0.tgz", + "integrity": "sha512-NAs9jCU+UeZ/ZmRb8R6zOp7N8eMklefdBYASnaRmCNXdgFE8w3OCxxZmLixkwqnGDHY5VF7hCulfw1Mls43N/A==", "dev": true, "requires": { - "@bazel/runfiles": "^6.3.1", + "@bazel/runfiles": "^6.5.0", "jszip": "^3.10.1", - "tmp": "^0.2.3", - "ws": "^8.18.2" + "tmp": "^0.2.5", + "ws": "^8.18.3" } }, "semver": { @@ -22108,16 +21793,24 @@ "dev": true }, "sinon": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.0.tgz", - "integrity": "sha512-TOgRcwFPbfGtpqvZw+hyqJDvqfapr1qUlOizROIk4bBLjlsjlB00Pg6wMFXNtJRpu+eCZuVOaLatG7M8105kAw==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.1.tgz", + "integrity": "sha512-Z0NVCW45W8Mg5oC/27/+fCqIHFnW8kpkFOq0j9XJIev4Ld0mKmERaZv5DMLAb9fGCevjKwaEeIQz5+MBXfZcDw==", "dev": true, "requires": { "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^13.0.5", - "@sinonjs/samsam": "^8.0.1", - "diff": "^7.0.0", + "@sinonjs/fake-timers": "^15.1.0", + "@sinonjs/samsam": "^8.0.3", + "diff": "^8.0.2", "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==", + "dev": true + } } }, "slash": { @@ -22410,9 +22103,9 @@ } }, "start-server-and-test": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.1.2.tgz", - "integrity": "sha512-OIjfo3G6QV9Sh6IlMqj58oZwVhPVuU/l6uVACG7YNE9kAfDvcYoPThtb0NNT3tZMMC3wOYbXnC15yiCSNFkdRg==", + "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==", "dev": true, "requires": { "arg": "^5.0.2", @@ -22422,7 +22115,7 @@ "execa": "5.1.1", "lazy-ass": "1.6.0", "ps-tree": "1.2.0", - "wait-on": "8.0.5" + "wait-on": "9.0.3" }, "dependencies": { "debug": { @@ -22779,9 +22472,9 @@ "dev": true }, "tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "dev": true }, "to-regex-range": { @@ -22873,9 +22566,9 @@ "dev": true }, "typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true }, "ua-parser-js": { @@ -23081,12 +22774,12 @@ } }, "wait-on": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-8.0.5.tgz", - "integrity": "sha512-J3WlS0txVHkhLRb2FsmRg3dkMTCV1+M6Xra3Ho7HzZDHpE7DCOnoSoCJsZotrmW3uRMhvIJGSKUKrh/MeF4iag==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-9.0.3.tgz", + "integrity": "sha512-13zBnyYvFDW1rBvWiJ6Av3ymAaq8EDQuvxZnPIw3g04UqGi4TyoIJABmfJ6zrvKo9yeFQExNkOk7idQbDJcuKA==", "dev": true, "requires": { - "axios": "^1.12.1", + "axios": "^1.13.2", "joi": "^18.0.1", "lodash": "^4.17.21", "minimist": "^1.2.8", @@ -23114,12 +22807,6 @@ "integrity": "sha512-ZzxBf288iALJseijWelmECm/1x7ZwQn3sMYIkDr2VvZp7r6SEKuT8D0O9Wiq6L9Nl5mazrOMcmiZE/2NCenaxw==", "dev": true }, - "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "dev": true - }, "webidl-conversions": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.0.tgz", diff --git a/package.json b/package.json index 4dd9a1a3f8..1fdfb77ce4 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.0", + "version": "4.11.1", "license": "MPL-2.0", "engines": { "node": ">=4" @@ -78,7 +78,7 @@ "build": "grunt", "patch": "npx patch-package", "unpatch": "npx patch-package --reverse", - "eslint": "eslint --color --format stylish '{lib,test,build,doc}/**/*.js' 'Gruntfile.js'", + "eslint": "eslint --color --format stylish '{lib,test,build,doc}/**/*.js' 'Gruntfile.js' '.github/bin/*.mjs'", "test": "npm run test:tsc && run-s \"test:unit:* -- {@}\" --", "test:tsc": "tsc", "test:unit": "karma start test/karma.conf.js", @@ -108,7 +108,6 @@ "version": "echo \"use 'npm run release' to bump axe-core version\" && exit 1", "release": "git fetch origin --tags --force && standard-version -a", "rule-gen": "node build/rule-generator", - "next-release": "standard-version --scripts.prebump=./build/next-version.js --skip.commit=true --skip.tag=true", "sri-update": "grunt build && node build/sri-update && git add sri-history.json", "sri-validate": "node build/sri-update --validate", "fmt": "prettier --write .", @@ -128,7 +127,6 @@ "@types/node": "^4.9.5", "aria-practices": "github:w3c/aria-practices#ce0336bd82d7d3651abcbde86af644197ddbc629", "aria-query": "^5.1.3", - "browser-driver-manager": "1.0.4", "chai": "^4.3.7", "chalk": "^4.x", "chromedriver": "latest", @@ -194,7 +192,7 @@ "*.{md,json,ts,html}": [ "prettier --write" ], - "*.js": [ + "*.{js,mjs}": [ "prettier --write", "eslint --fix" ] diff --git a/sri-history.json b/sri-history.json index d1557eace1..0d46b48166 100644 --- a/sri-history.json +++ b/sri-history.json @@ -398,5 +398,9 @@ "4.11.0": { "axe.js": "sha256-RKE4K0g6QAePcUi+Tcnr567YKVEwnoToqe+Qd7w1mzo=", "axe.min.js": "sha256-6eWGPDOodPCbwBrNkjS348hxR59e74gC+lglREZebQE=" + }, + "4.11.1": { + "axe.js": "sha256-bewBszbrmr6wbpqv1M8r6njtgyYKf31B+ggoTFBXKe8=", + "axe.min.js": "sha256-QF8ptuZ3j6HwqxQMh03I7NlPAojgoaGGzRnGkTHmR9U=" } } diff --git a/test/act-rules/act-runner.js b/test/act-rules/act-runner.js index 238e96175a..3d3eab094c 100644 --- a/test/act-rules/act-runner.js +++ b/test/act-rules/act-runner.js @@ -28,11 +28,8 @@ module.exports = ({ id, title, axeRules, skipTests = [] }) => { this.timeout(50000); this.retries(3); - before(async () => { - driver = getWebdriver(); - }); - before(done => { + driver = getWebdriver(); server = http.createServer((request, response) => { return handler(request, response, { cleanUrls: false, diff --git a/test/checks/color/color-contrast.js b/test/checks/color/color-contrast.js index 312674d66c..c7e2dd6bf5 100644 --- a/test/checks/color/color-contrast.js +++ b/test/checks/color/color-contrast.js @@ -15,6 +15,45 @@ describe('color-contrast', function () { axe._tree = undefined; }); + it('should return undefined if cannot handle color', function () { + var params = checkSetup( + '
' + + 'My text
' + ); + + var expectedRelatedNodes = fixture.querySelector('#divundertest'); + assert.isUndefined(contrastEvaluate.apply(checkContext, params)); + assert.deepEqual(checkContext._relatedNodes, [expectedRelatedNodes]); + assert.deepEqual(checkContext._data.messageKey, 'colorParse'); + assert.equal( + checkContext._data.colorParse, + 'oklch(0.961073 0.000047911 none / 0.2)' + ); + }); + + it('should return undefined if cannot handle backgroundcolor', function () { + var params = checkSetup( + '
' + + 'My text
' + ); + assert.isUndefined(contrastEvaluate.apply(checkContext, params)); + assert.deepEqual(checkContext._relatedNodes, []); + assert.deepEqual(checkContext._data.messageKey, 'colorParse'); + assert.equal( + checkContext._data.colorParse, + 'oklch(0.961073 0.000047911 none / 0.2)' + ); + }); + + it('should return undefined if cannot handle text-shadow', function () { + var params = checkSetup( + '
My text
' + ); + + assert.isUndefined(contrastEvaluate.apply(checkContext, params)); + assert.deepEqual(checkContext._relatedNodes, []); + }); + it('should return true for hidden element', function () { var params = checkSetup( '
' + diff --git a/test/commons/color/color.js b/test/commons/color/color.js index 3c1722c113..c7057bb69a 100644 --- a/test/commons/color/color.js +++ b/test/commons/color/color.js @@ -301,6 +301,19 @@ describe('color.Color', () => { assert.equal(c.blue, 144); assert.equal(c.alpha, 0.5); }); + + it('clips out of gamut values', () => { + const c = new Color(); + c.parseColorFnString('oklch(25% 0.75 345)'); + assert.equal(c.red, 186); + assert.equal(c.green, 0); + assert.equal(c.blue, 103); + assert.equal(c.alpha, 1); + + assert.equal(c.red, Math.round(c.r * 255)); + assert.equal(c.green, Math.round(c.g * 255)); + assert.equal(c.blue, Math.round(c.b * 255)); + }); }); }); diff --git a/test/get-webdriver.js b/test/get-webdriver.js index 6ead098e7c..c71a55710a 100644 --- a/test/get-webdriver.js +++ b/test/get-webdriver.js @@ -1,16 +1,21 @@ const { Builder } = require('selenium-webdriver'); const chrome = require('selenium-webdriver/chrome'); -const chromedriverPath = require('chromedriver').path; +const chromedriverPath = + process.env.CHROMEDRIVER_BIN ?? require('chromedriver').path; const getWebdriver = () => { const service = new chrome.ServiceBuilder(chromedriverPath); + const options = new chrome.Options().addArguments('--headless'); - const webdriver = new Builder() - .setChromeOptions(new chrome.Options().addArguments('headless')) + if (process.env.CHROME_BIN) { + options.setBinaryPath(process.env.CHROME_BIN); + } + + return new Builder() + .setChromeOptions(options) .forBrowser('chrome') .setChromeService(service) .build(); - return webdriver; }; module.exports.getWebdriver = getWebdriver; diff --git a/test/integration/full/contrast/prototype.html b/test/integration/full/contrast/prototype.html index f7f915d6bf..5c1f665783 100644 --- a/test/integration/full/contrast/prototype.html +++ b/test/integration/full/contrast/prototype.html @@ -24,7 +24,7 @@ -
Text
+
Text
diff --git a/test/integration/full/preload-cssom/preload-cssom.js b/test/integration/full/preload-cssom/preload-cssom.js index 24a998063c..63e25b11a5 100644 --- a/test/integration/full/preload-cssom/preload-cssom.js +++ b/test/integration/full/preload-cssom/preload-cssom.js @@ -40,6 +40,10 @@ describe('preload cssom integration test', function () { styleTagWithCyclicCrossOriginImports: { id: 'styleTagWithCyclicCrossOriginImports', text: '@import "cyclic-cross-origin-import-1.css";' + }, + styleTagWithNonExistentImport: { + id: 'styleTagWithNonExistentImport', + text: '@import "non-existent-import.css";' } }; let stylesForPage; @@ -141,12 +145,7 @@ describe('preload cssom integration test', function () { }); it('throws if cross-origin stylesheet fail to load', done => { - stylesForPage = [ - { - id: 'nonExistingStylesheet', - text: '@import "import-non-existing-cross-origin.css";' - } - ]; + stylesForPage = [styleSheets.styleTagWithNonExistentImport]; attachStylesheets( { root: root, @@ -157,8 +156,12 @@ describe('preload cssom integration test', function () { done(err); } getPreloadCssom(root) - .then(() => { - done(new Error('Expected getPreload to reject.')); + .then(sheets => { + done( + new Error( + `Expected getPreload to reject, but it resolved with ${JSON.stringify(sheets)}.` + ) + ); }) .catch(e => { assert.isDefined(e); diff --git a/test/integration/full/test-webdriver.js b/test/integration/full/test-webdriver.js index 89d9e8a863..5a85fe5b61 100644 --- a/test/integration/full/test-webdriver.js +++ b/test/integration/full/test-webdriver.js @@ -1,7 +1,8 @@ const { globSync } = require('glob'); const chrome = require('selenium-webdriver/chrome'); const firefox = require('selenium-webdriver/firefox'); -const chromedriver = require('chromedriver'); +const chromedriver = + process.env.CHROMEDRIVER_BIN ?? require('chromedriver').path; const args = process.argv.slice(2); @@ -118,22 +119,32 @@ function buildWebDriver(browser) { let webdriver; const mobileBrowser = browser.split('-mobile'); - // fix chrome DevToolsActivePort file doesn't exist in CricleCI (as well as a + // fix chrome DevToolsActivePort file doesn't exist in CircleCI (as well as a // host of other problems with starting Chrome). the only thing that seems to // allow Chrome to start without problems consistently is using ChromeHeadless // @see https://stackoverflow.com/questions/50642308/webdriverexception-unknown-error-devtoolsactiveport-file-doesnt-exist-while-t if (browser === 'chrome') { - const service = new chrome.ServiceBuilder(chromedriver.path).build(); + const service = new chrome.ServiceBuilder(chromedriver).build(); const options = new chrome.Options().addArguments([ - 'headless', + '--headless', '--no-sandbox', '--disable-extensions', '--disable-dev-shm-usage' ]); + + if (process.env.CHROME_BIN) { + options.setBinaryPath(process.env.CHROME_BIN); + } + webdriver = chrome.Driver.createSession(options, service); } else if (browser === 'firefox') { const options = new firefox.Options().addArguments('--headless'); + + if (process.env.FIREFOX_BIN) { + options.setBinary(process.env.FIREFOX_BIN); + } + webdriver = firefox.Driver.createSession(options); } diff --git a/test/integration/rules/color-contrast/color-contrast.html b/test/integration/rules/color-contrast/color-contrast.html index bf47ee73ce..20b7082e7a 100644 --- a/test/integration/rules/color-contrast/color-contrast.html +++ b/test/integration/rules/color-contrast/color-contrast.html @@ -282,6 +282,44 @@
+
+ This is a foreground colorParse fail! +
+ +
+ This is a background colorParse fail! +
+ +
+ This is a text-shadow colorParse fail! +
+

note: gives firefox to load (document.stylesheets), other browsers are fine. + // In Firefox, there is a delay between adding the element and it appearing in + // document.styleSheets, so we poll until we see it there. + const timeoutAt = Date.now() + 500; + const interval = setInterval(function () { + const isLoaded = Array.from(doc.styleSheets).some( + sheet => sheet.ownerNode === style + ); + if (isLoaded) { + clearInterval(interval); + resolve(); + } else if (Date.now() > timeoutAt) { + clearInterval(interval); + reject( + new Error( + 'Added