diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 67d5a1dca..642aa5b1b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -57,13 +57,6 @@ updates: shipped-minor-and-patch: patterns: ['fuse.js', 'mediabunny', 'sortablejs'] update-types: ['minor', 'patch'] - # Stryker's packages come out together, and each requires the others at its own - # version exactly (@stryker-mutator/vitest-runner's peerDependencies): one pull - # request for all of them, majors included. Before tooling-minor-and-patch, which - # would take them otherwise. While the vitest runner carries a patch, both are - # ignored below and move together through the Patched libraries workflow. - stryker: - patterns: ['@stryker-mutator/*'] # WebdriverIO's packages come out together and only work at the same version: one pull # request for all of them, majors included (10.0.0 came as four, each red alone, # 2026-10-10). Before tooling-minor-and-patch, which would take them otherwise. @@ -79,14 +72,10 @@ updates: # from the Patched libraries workflow instead, which re-cuts the patch with # tools/recut-patch.mjs and opens the pull request itself when that is clean # (docs/updating-patched-libraries.md). Keep this list in step with - # patchedDependencies, and the packages that move with a patched one (LOCKSTEP in - # tools/check-patched-updates.mjs: @stryker-mutator/core with the vitest runner, which - # requires its exact version). When every change of a patch has landed upstream, - # tools/recut-patch.mjs drops the patch and takes the library and those packages off - # this list in the same pull request. + # patchedDependencies. When every change of a patch has landed upstream, + # tools/recut-patch.mjs drops the patch and takes the library off this list in the same + # pull request. ignore: - - dependency-name: '@stryker-mutator/core' - - dependency-name: '@stryker-mutator/vitest-runner' - dependency-name: 'Coloris' - dependency-name: 'dashjs' - dependency-name: 'gif.js' diff --git a/.github/workflows/firefox-beta.yml b/.github/workflows/firefox-beta.yml index 987905f20..ba5406514 100644 --- a/.github/workflows/firefox-beta.yml +++ b/.github/workflows/firefox-beta.yml @@ -131,8 +131,8 @@ jobs: fi exit 0 fi - # A suite that runs out of its time ends cancelled, not failed (as in - # mutation-tests.yml): a Firefox that hangs the suites said nothing. + # A suite that runs out of its time ends cancelled, not failed: a Firefox that + # hangs the suites said nothing. if [ "$RESULT" != failure ] && [ "$RESULT" != cancelled ]; then echo "e2e result: $RESULT - nothing to report." exit 0 diff --git a/.github/workflows/firefox-stable.yml b/.github/workflows/firefox-stable.yml index d295bfe50..d269c3eeb 100644 --- a/.github/workflows/firefox-stable.yml +++ b/.github/workflows/firefox-stable.yml @@ -192,8 +192,8 @@ jobs: done exit 0 fi - # A suite that runs out of its time ends cancelled, not failed (as in - # mutation-tests.yml): a Firefox that hangs the suites said nothing. + # A suite that runs out of its time ends cancelled, not failed: a Firefox that + # hangs the suites said nothing. if [ "$RESULT" != failure ] && [ "$RESULT" != cancelled ]; then echo "e2e result: $RESULT - nothing to report." exit 0 diff --git a/.github/workflows/mutation-tests.yml b/.github/workflows/mutation-tests.yml deleted file mode 100644 index 0e0f9a2c9..000000000 --- a/.github/workflows/mutation-tests.yml +++ /dev/null @@ -1,204 +0,0 @@ -name: Mutation tests - -# Once a week, Stryker (stryker.config.mjs) changes the pure-logic modules one thing at a -# time - a comparison, a bound, a call left out - and runs the unit tests against each -# change. A change they still pass is a place where a fix could ship without a test that -# fails without it: the rule every fix here follows, checked by hand until now (T4). -# -# A report, not a gate: the run summary gets a table per file, the full HTML reports are the -# mutation-reports- artifacts (30 days), and when the tests missed mutants, one issue, -# "Mutation testing: week to ", assigned to the owner and @mentioning them, lists them. -# The next week's issue closes it, and so does a week in which every mutant was caught. -# -# The modules are in four areas, one shard each (stryker.config.mjs, SHARDS), each run by a -# job of its own side by side; the report job puts their reports together. With the command -# runner every mutant ran the whole unit suite, and seven shards took 2 to 4.7 hours (#349); -# with the vitest runner, a mutant runs only the tests that reach it, and the same seven took -# 2 to 10 minutes (2026-10-06). The mpv host keeps the command runner (its message loop runs -# in a process its tests start), about an hour and a half. - -on: - schedule: - - cron: '40 6 * * 1' - workflow_dispatch: - -permissions: - contents: read # the checkout - -concurrency: - group: mutation-tests - cancel-in-progress: false - -jobs: - mutation: - name: Stryker over the ${{ matrix.shard }} modules - runs-on: ubuntu-latest - # Minutes for a vitest-runner shard; the host's command-runner shard about an hour and a - # half (stryker.config.mjs). 350 minutes leaves room, under the runners' 360. - timeout-minutes: 350 - strategy: - # One shard that fails or runs out of time leaves the others' reports. - fail-fast: false - matrix: - shard: [core-1, network-1, tools-1, host-1] - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 - - - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 - with: - node-version-file: .nvmrc - check-latest: true - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Run Stryker - env: - STRYKER_SHARD: ${{ matrix.shard }} - run: pnpm run test:mutation - - - name: Upload the mutation report - if: always() - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - with: - name: mutation-reports-${{ matrix.shard }} - path: reports/mutation/ - if-no-files-found: ignore - retention-days: 30 - - report: - name: The week's report - needs: mutation - # The shards that wrote a report are reported, also when another one failed. - if: always() - runs-on: ubuntu-latest - timeout-minutes: 15 - # Only this job writes: the shards run the code under test and need nothing but the checkout. - permissions: - contents: read # the checkout - issues: write # the week's issue, and this workflow's own failure - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - OWNER: ${{ github.repository_owner }} - PREFIX: 'Mutation testing: week to ' - RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 - with: - node-version-file: .nvmrc - check-latest: true - - - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 - with: - pattern: mutation-reports-* - path: shards - - - name: Put the shards' reports together - run: | - set -euo pipefail - found=0 - missing='' - for shard in core-1 network-1 tools-1 host-1; do - if [ -f "shards/mutation-reports-$shard/mutation.json" ]; then - found=$((found + 1)) - else - missing="$missing $shard" - fi - done - echo "MISSING_SHARDS=${missing# }" >> "$GITHUB_ENV" - if [ "$found" -gt 0 ]; then - node tools/merge-mutation-reports.mjs - fi - - - name: Write the summary - run: | - set -euo pipefail - if [ -n "$MISSING_SHARDS" ]; then - echo "No mutation report from: $MISSING_SHARDS (Stryker stopped before writing one)." >> "$GITHUB_STEP_SUMMARY" - echo >> "$GITHUB_STEP_SUMMARY" - fi - if [ -f reports/mutation/mutation.json ]; then - node tools/mutation-report.mjs reports/mutation/mutation.json summary >> "$GITHUB_STEP_SUMMARY" - fi - - - name: Open, update or close the week's issue - run: | - set -euo pipefail - if [ ! -f reports/mutation/mutation.json ]; then - echo "No shard wrote a report." - exit 0 - fi - today=$(date -u +%F) - title="$PREFIX$today" - missed=$(node tools/mutation-report.mjs reports/mutation/mutation.json count) - - # Every issue this workflow opened, open or closed. - gh api --paginate "repos/$GH_REPO/issues?state=all&per_page=100" \ - --jq '.[] | select(.pull_request == null and .user.login == "github-actions[bot]" and (.title | startswith(env.PREFIX))) | [.number, .state, .title] | @tsv' \ - > "$RUNNER_TEMP/mine.tsv" - - # A shard without a report says nothing of its mutants: its week is not done. - if [ "$missed" -eq 0 ] && [ -n "${MISSING_SHARDS:-}" ]; then - echo "Every mutant of the reports was caught; no report from: $MISSING_SHARDS." - exit 0 - fi - if [ "$missed" -eq 0 ]; then - echo "The unit tests caught every mutant." - while IFS=$'\t' read -r number state old; do - if [ "$state" != open ]; then continue; fi - gh issue close "$number" --reason completed --comment "The unit tests caught every mutant in the week to $today: $RUN_URL" - echo "Closed #$number ($old)" - done < "$RUNNER_TEMP/mine.tsv" - exit 0 - fi - - node tools/mutation-report.mjs reports/mutation/mutation.json issue "$OWNER" "$RUN_URL" > "$RUNNER_TEMP/body.md" - current=$(awk -F '\t' -v title="$title" '$2 == "open" && $3 == title {print $1; exit}' "$RUNNER_TEMP/mine.tsv") - if [ -n "$current" ]; then - gh issue edit "$current" --body-file "$RUNNER_TEMP/body.md" - echo "Updated #$current" - else - url=$(gh issue create --title "$title" --assignee "$OWNER" --body-file "$RUNNER_TEMP/body.md") - current=${url##*/} - echo "Opened $url" - fi - - # The last weeks' open issues: this one replaces them. - while IFS=$'\t' read -r number state old; do - if [ "$state" != open ] || [ "$number" = "$current" ]; then continue; fi - gh issue close "$number" --reason completed --comment "#$current lists the week to $today." - echo "Closed #$number ($old)" - done < "$RUNNER_TEMP/mine.tsv" - - # A failed run of this workflow is emailed only to whoever started it (for the schedule, - # whoever last changed the cron line): one issue while it is open, assigned and - # @mentioning the owner, as toolchain-updates.yml does. A failure while it is open adds a - # comment to it. A shard that failed or ran out of time counts too (the latter ends - # cancelled, see the condition). - - name: Report this workflow's own failure - # cancelled: a shard that ran out of its time ends cancelled, not failed, and such a run - # (no report at all, 2026-10-05) said nothing. - if: failure() || needs.mutation.result == 'failure' || needs.mutation.result == 'cancelled' - env: - TITLE: 'Mutation tests workflow failed' - run: | - set -euo pipefail - number=$(gh issue list --state open --limit 200 --json number,title \ - --jq '[.[] | select(.title == env.TITLE)][0].number // empty') || number='' - if [ -n "$number" ]; then - printf '@%s Failed again: %s\n' "$OWNER" "$RUN_URL" > "$RUNNER_TEMP/comment.md" - gh issue comment "$number" --body-file "$RUNNER_TEMP/comment.md" - exit 0 - fi - printf '@%s mutation-tests.yml failed: %s\n\nThe run log names the failed command. Close this issue once it is fixed; a later failure opens a new one.\n' \ - "$OWNER" "$RUN_URL" > "$RUNNER_TEMP/body.md" - gh issue create --title "$TITLE" --assignee "$OWNER" --body-file "$RUNNER_TEMP/body.md" diff --git a/.github/workflows/runner-images.yml b/.github/workflows/runner-images.yml index 58325aee2..dc98036f7 100644 --- a/.github/workflows/runner-images.yml +++ b/.github/workflows/runner-images.yml @@ -226,8 +226,8 @@ jobs: } report() { # result, images, what the image is to -latest local result=$1 images=$2 role=$3 title number - # A job that runs out of its time ends cancelled, not failed (as in - # mutation-tests.yml): an image that hangs CI said nothing. + # A job that runs out of its time ends cancelled, not failed: an image that + # hangs CI said nothing. if [ "$result" != success ] && [ "$result" != failure ] && [ "$result" != cancelled ]; then echo "$images: ${result:-not run} - nothing to report." return diff --git a/.gitignore b/.gitignore index 7b5996149..299371c11 100644 --- a/.gitignore +++ b/.gitignore @@ -40,9 +40,5 @@ lint-*.json # vitest --coverage output. coverage/ -# Stryker (pnpm run test:mutation): its reports and its sandboxes -reports/mutation/ -.stryker-tmp/ - # The helper's launch lock (faststream-mpv-host.mjs launchLockFile), next to it while mpv starts. native-host/faststream-mpv-launch-*.lock diff --git a/docs/maintenance.md b/docs/maintenance.md index 073405a38..d7fa15bd6 100644 --- a/docs/maintenance.md +++ b/docs/maintenance.md @@ -207,12 +207,6 @@ third attempt was cancelled too or GitHub refused the re-run: re-run it from the tab, and the issue closes at the next green CI run on `main`. "Auto release failed" means such a run was red or its release failed; the issue links the run. -Once a week, `mutation-tests.yml` changes the code the unit tests cover one thing at a -time and checks the tests notice. When they miss some, "Mutation testing: week to " -lists them: each is a place a fix could ship without a test that fails without it. Nothing -waits on it; the next week's issue replaces it, and a week with every change caught closes -it. - ## What update-prs.yml checks before it says "ready to merge" Nothing merges itself (the owner's choice, 2026-10-02; from 2026-10-01 every kind of update diff --git a/docs/notes/mpv.md b/docs/notes/mpv.md index 5d1a6903a..568f10178 100644 --- a/docs/notes/mpv.md +++ b/docs/notes/mpv.md @@ -34,8 +34,7 @@ the new hashes). The installer counts because `update-local.ps1` tells an instal from the repository's by the host file alone; a raised `HostVersion` changes that file. The extension changes with it, so such a push releases, Firefox updates the extension, and the next hand-off on the owner's PC shows the "!" until `update-local.cmd` (or -`install.ps1`) has run. The hash check is skipped in Stryker's sandbox, whose copy of -the host holds every mutant. +`install.ps1`) has run. **The thin helper (host 15, 2026-10-13).** The host changed 14 times in 10 days, each one a reinstall by hand, because policy lived in it. The owner chose to move the policy into the diff --git a/docs/notes/workflows.md b/docs/notes/workflows.md index 8783c15c0..67efd2588 100644 --- a/docs/notes/workflows.md +++ b/docs/notes/workflows.md @@ -327,8 +327,7 @@ start: gh can give a log with every step "UNKNOWN STEP"). Without E2E_SHARD a config runs all its spec files (local `pnpm run verify`). The private browsing suite (one spec file) runs in the first extension group only. A run is 18 jobs - at once of the account's 20, so more groups would only queue; the weekly mutation run - (Mondays, 7 jobs for hours) leaves 13, and a push during it runs in two waves. + at once of the account's 20, so more groups would only queue. `fail-fast: false`, so one failing group does not cancel the others and their lists of retried specs. Per-job artifacts: `e2e-retried---`, `e2e-logs---`; `e2e-moz-logs-windows--` only from the Windows @@ -647,37 +646,8 @@ - All of it was dry-run with a stub `gh` against the real upstream history (sync: adopted -> closed, push -> no rebuild, new release named, comment only on upstream movement; patched libraries: open once, no duplicates, close when caught up or unpatched). -- **`mutation-tests.yml`** (Mondays 06:40 UTC), 2026-10-01, T4: Stryker - (`stryker.config.mjs`, `pnpm run test:mutation`) over 25 pure-logic modules with unit - tests (10 small ones added 2026-10-03, #253; the config says which wait, and why). A report, not a gate: the run summary gets a table per file - (`tools/mutation-report.mjs`), the HTML report is the `mutation-reports` artifact, and when - the unit tests missed mutants (survived, or no test reaches them), one issue "Mutation - testing: week to " lists them, assigned + @mention; next week's replaces it, a week - with all caught closes it. **The command runner**, not the vitest one: every mutant runs the - whole unit suite (`__STRYKER_ACTIVE_MUTANT__`), about 1.2 s each with 4 workers locally - on - CI a mutant the tests miss runs the whole ~18 s suite, and one job per area ran out of its - 240 minutes at 51-74% with no report (#349, 2026-10-05): since then the three areas are - seven shards (`PARTS` in the config, split by file size), each in a job of 350 minutes, and - a shard that runs out of time (it ends cancelled) is reported as a failure. **Since - 2026-10-06 the vitest runner** with per-test coverage: a mutant runs only the tests that - reached its code, in a Vitest that stays up (143 mutants in 31 s locally, ~12.5 tests a - mutant). Its 10.0.0 release (August 2026) predates vitest 5, which joins a test's suite - chain with ' > ', so its test filter matched nothing and every mutant "survived" - (stryker-js #6210); FastStream carries the fix, stryker-js PR #6214, as a pnpm patch - (`patches/@stryker-mutator__vitest-runner@10.0.0.patch`, the compiled files). When a - release has it, the Patched libraries workflow opens the pull request that drops the patch, - moves @stryker-mutator/core along (LOCKSTEP in `tools/check-patched-updates.mjs`: the runner - requires its core's exact version) and hands both back to Dependabot, whose `stryker` group - then keeps all of Stryker's packages in one pull request. A test that runs a module as a - process of its own (mpvHostVersion's host; the Windows-only installer and update-local - tests) does not see a mutant there. Compared mutant by mutant (command-runner run - 37384050152, 4.7 hours; vitest-runner run 37393654214, 10 minutes): 11,313 of 11,370 alike. - The rest: each tool's entry line (`if (process.argv[1] ...`) a crashed run where the command - runner caught, two swapped on one line of SubtitleUtils - and the mpv host's message loop - (`main()`, `sendMessage()`), 24 mutants with no test reaching them. So the host is an area of - its own on the command runner (`COMMAND_AREAS`, `host-1`, about an hour and a half), and core, - network and tools are one vitest-runner shard each: four jobs. The sandbox leaves out `tsconfig.json`: Stryker rewrites it through - TypeScript's JS API, which TypeScript 7 does not have. `tests/workflows/mutation-tests.test.sh`. - Baseline, 2026-10-01 (73 min locally): 71.8% of 3,614 mutants caught; the weakest are the - mpv host (47.7%), MpvBackend (58.4%), SubtitleUtils (63.2%) and TabTracker (68.4%), the - best SubtitleSyncUtils (96%), MultiRegexMatcher, UrlMatchList and StreamPick (92%). +- **`mutation-tests.yml`** (2026-10-01 to 2026-10-22): Stryker over the unit-tested modules, + weekly. Removed with Stryker: its reports (about 4,700 mutants not caught, 64.6% to 68%) + were closed by hand each week and no fix came from them, while it carried a 131-line patch + of its vitest runner, an override and 34 MB of packages. The fixes kept their own check: a + hand-made mutation of each one, which its test must catch. diff --git a/docs/updating-patched-libraries.md b/docs/updating-patched-libraries.md index 22ba2202d..37f18db8e 100644 --- a/docs/updating-patched-libraries.md +++ b/docs/updating-patched-libraries.md @@ -62,15 +62,10 @@ regenerated files in `chrome/player/modules/`. Then commit on a branch and open request (the regenerated files are git-ignored, so they are not part of the commit). When every one of FastStream's changes has landed upstream, `--apply` drops the -patch instead of committing one, takes the library (and what moves with it, below) off +patch instead of committing one, takes the library off `.github/dependabot.yml`'s ignore list, and says to remove any `patched: true` marks in `tools/sync-vendor.mjs`. -Some packages must stay at a patched library's exact version: `LOCKSTEP` in -`tools/check-patched-updates.mjs` (`@stryker-mutator/core` with -`@stryker-mutator/vitest-runner`, which requires its core's version exactly). `--apply` -moves them to the library's new version in the same pull request, and Dependabot ignores -them while the library is patched, where it would bump them alone. If `tools/sync-vendor.mjs` then fails (an unpatched file renamed too), the tool exits 2 with the version, lockfile and patch already changed: fix `sync-vendor.mjs`, then run `pnpm run verify`. diff --git a/eslint.config.js b/eslint.config.js index 4c0f6ba6a..1e3b90e51 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -19,8 +19,6 @@ module.exports = [ '.git/', '.vscode/', '.claude/', - // Stryker's copies of the repo; one outlives a run that could not delete it. - '.stryker-tmp/', // The e2e fixtures are all generated (gitignored): the media buildFixtures makes, and the // hls.js and dash.js releases the live suite downloads (live-libs), 136,000 errors. 'tests/e2e/fixtures/', diff --git a/package.json b/package.json index 3a45cf9b4..ff640faa5 100644 --- a/package.json +++ b/package.json @@ -38,8 +38,7 @@ "verify:fsaunpack": "node tools/verify-fsaunpack.mjs", "sign:amo": "node tools/sign-amo.mjs", "sign:amo:listed": "node tools/sign-amo.mjs --listed", - "release": "node tools/cut-release.mjs", - "test:mutation": "stryker run" + "release": "node tools/cut-release.mjs" }, "repository": { "type": "git", @@ -51,8 +50,6 @@ }, "homepage": "https://github.com/Nawid3333/FastStream#readme", "devDependencies": { - "@stryker-mutator/core": "10.0.0", - "@stryker-mutator/vitest-runner": "10.0.0", "@stylistic/eslint-plugin": "^5.10.0", "@types/chrome": "^0.3.5", "@types/node": "^26.6.5", diff --git a/patches/@stryker-mutator__vitest-runner@10.0.0.patch b/patches/@stryker-mutator__vitest-runner@10.0.0.patch deleted file mode 100644 index 0c9f478af..000000000 --- a/patches/@stryker-mutator__vitest-runner@10.0.0.patch +++ /dev/null @@ -1,131 +0,0 @@ -diff --git a/dist/src/stryker-setup.js b/dist/src/stryker-setup.js -index aecfacbe47b285c272c47e54b3d66a716adfdc41..57b0f9897c29d8fd0303082945362893c4f1e622 100644 ---- a/dist/src/stryker-setup.js -+++ b/dist/src/stryker-setup.js -@@ -7,6 +7,8 @@ const mode = inject('mode'); - const ns = globalThis[globalNamespace] || (globalThis[globalNamespace] = {}); - ns.hitLimit = inject('hitLimit'); - const isGreaterThanVitest4Point1 = inject('isGreaterThanVitest4Point1'); -+// Must match the separator the runner filters with; see test-helpers.js -+const testNameSeparator = inject('testNameSeparator'); - if (mode === 'mutant') { - beforeAll(() => { - ns.hitCount = 0; -@@ -36,7 +38,7 @@ if (mode === 'mutant') { - else { - ns.activeMutant = undefined; - beforeEach(({ task }) => { -- ns.currentTestId = toRawTestId(task); -+ ns.currentTestId = toRawTestId(task, testNameSeparator); - }); - afterEach(() => { - ns.currentTestId = undefined; -@@ -56,16 +58,16 @@ else { - } - } - // Stryker disable all: this file is copied to the sandbox dir --function collectTestName({ name, suite, }) { -+function collectTestName({ name, suite, }, separator) { - const nameParts = [name]; - let currentSuite = suite; - while (currentSuite) { - nameParts.unshift(currentSuite.name); - currentSuite = currentSuite.suite; - } -- return nameParts.join(' ').trim(); -+ return nameParts.join(separator).trim(); - } --function toRawTestId(test) { -- return `${test.file?.filepath ?? 'unknown.js'}#${collectTestName(test)}`; -+function toRawTestId(test, separator) { -+ return `${test.file?.filepath ?? 'unknown.js'}#${collectTestName(test, separator)}`; - } - //# sourceMappingURL=stryker-setup.js.map -\ No newline at end of file -diff --git a/dist/src/test-helpers.js b/dist/src/test-helpers.js -index 56cc786f30c524ae18ce87eef1a67fdf26b703c5..87c7756220c1a3d7b8121acc6462042417029d22 100644 ---- a/dist/src/test-helpers.js -+++ b/dist/src/test-helpers.js -@@ -1,16 +1,21 @@ - // Don't merge this file into 'vitest-helpers.ts'! - // This file is used from the testing environment (via stryker-setup.js) and thus could be loaded into the browser (when using vitest with browser mode). - // Thus we should avoid unnecessary dependencies in this file. --export function collectTestName({ name, suite, }) { -+// The separator Vitest itself uses between the suite chain and the test name: Vitest 5 -+// matches `testNamePattern` against the chain joined with ' > '; before, a plain space. -+// (stryker-js PR #6214, carried as a pnpm patch until a release has it.) -+export const VITEST_5_TEST_NAME_SEPARATOR = ' > '; -+export const LEGACY_TEST_NAME_SEPARATOR = ' '; -+export function collectTestName({ name, suite, }, separator = LEGACY_TEST_NAME_SEPARATOR) { - const nameParts = [name]; - let currentSuite = suite; - while (currentSuite) { - nameParts.unshift(currentSuite.name); - currentSuite = currentSuite.suite; - } -- return nameParts.join(' ').trim(); -+ return nameParts.join(separator).trim(); - } --export function toRawTestId(test) { -- return `${test.file?.filepath ?? 'unknown.js'}#${collectTestName(test)}`; -+export function toRawTestId(test, separator = LEGACY_TEST_NAME_SEPARATOR) { -+ return `${test.file?.filepath ?? 'unknown.js'}#${collectTestName(test, separator)}`; - } - //# sourceMappingURL=test-helpers.js.map -\ No newline at end of file -diff --git a/dist/src/vitest-helpers.js b/dist/src/vitest-helpers.js -index fa4f8138ab3b2aba64f4e715be2d8126da6ccf8b..14349c6e0e51b20369a3e10a5b91f0c8b671aa28 100644 ---- a/dist/src/vitest-helpers.js -+++ b/dist/src/vitest-helpers.js -@@ -17,11 +17,11 @@ function convertTaskStateToTestStatus(taskState, testMode) { - } - return TestStatus.Failed; - } --export function convertTestToTestResult(test) { -+export function convertTestToTestResult(test, separator) { - const status = convertTaskStateToTestStatus(test.result?.state, test.mode); - const baseTestResult = { -- id: normalizeTestId(toRawTestId(test)), -- name: collectTestName(test), -+ id: normalizeTestId(toRawTestId(test, separator)), -+ name: collectTestName(test, separator), - timeSpentMs: test.result?.duration ?? 0, - fileName: test.file?.filepath && path.resolve(test.file.filepath), - }; -diff --git a/dist/src/vitest-test-runner.js b/dist/src/vitest-test-runner.js -index 84f1ca026503b8e92b7adc952ec6c6a401943656..3fabeb45098fa483aee07dce4b74fad7cebdce10 100644 ---- a/dist/src/vitest-test-runner.js -+++ b/dist/src/vitest-test-runner.js -@@ -7,6 +7,15 @@ import { commonTokens, tokens, } from '@stryker-mutator/api/plugin'; - import { DryRunStatus, toMutantRunResult, determineHitLimitReached, TestStatus, } from '@stryker-mutator/api/test-runner'; - import { errorToString, escapeRegExp, normalizeFileName, notEmpty, testFilesProvided, } from '@stryker-mutator/util'; - import { vitestWrapper } from './vitest-wrapper.js'; -+import { LEGACY_TEST_NAME_SEPARATOR, VITEST_5_TEST_NAME_SEPARATOR, } from './test-helpers.js'; -+// Vitest 5 matches `testNamePattern` against the suite chain joined with ' > ' rather -+// than a space, so a filter built from space-joined names matches nothing and every -+// covered mutant runs zero tests (stryker-js #6210, PR #6214). -+function testNameSeparator() { -+ return semver.satisfies(vitestWrapper.version, '>=5.0.0') -+ ? VITEST_5_TEST_NAME_SEPARATOR -+ : LEGACY_TEST_NAME_SEPARATOR; -+} - import { convertTestToTestResult, fromTestId, collectTestsFromSuite, normalizeCoverage, isErrorCodeError, VITEST_ERROR_CODES, } from './vitest-helpers.js'; - const STRYKER_SETUP = fileURLToPath(new URL('./stryker-setup.js', import.meta.url)); - export class VitestTestRunner { -@@ -83,6 +92,7 @@ export class VitestTestRunner { - }); - this.ctx.provide('globalNamespace', this.globalNamespace); - this.ctx.provide('isGreaterThanVitest4Point1', semver.satisfies(vitestWrapper.version, '>=4.1.0')); -+ this.ctx.provide('testNameSeparator', testNameSeparator()); - this.ctx.config.browser.screenshotFailures = false; - this.ctx.projects.forEach((project) => { - project.config.setupFiles = [ -@@ -173,7 +183,7 @@ export class VitestTestRunner { - .filter((test) => test.result); // if no result: it was skipped because of bail - let failure = false; - const testResults = tests.map((test) => { -- const testResult = convertTestToTestResult(test); -+ const testResult = convertTestToTestResult(test, testNameSeparator()); - failure ||= testResult.status === TestStatus.Failed; - return testResult; - }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf2139de2..2d1851595 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,13 +10,11 @@ overrides: extract-zip: npm:@electron-internal/extract-zip@^1.0.5 undici@6: ^6.28.1 undici@7: ^7.29.1 - qs: ^6.16.0 basic-ftp: ^6.2.1 shell-quote: ^1.11.0 web-ext>@devicefarmer/adbkit: '-' patchedDependencies: - '@stryker-mutator/vitest-runner@10.0.0': c5d635178da5a48e07051030a6d2eb3f33f4b31a71f4232c05f099e8e90f3dc2 Coloris@0.25.0: d8a066fa49aa80466d054aad0f7a2c767b2f62cf365492c155bb9b4ce30fb2ec dashjs@5.2.1: f09c7ddbd4aedea040b042bfc600ab65b3b6131d6bfdd8dbfaf3ea580fd20ffc gif.js@0.2.0: 7f90135cc94c36690ec1e9725f81b9ec0386d2b62e08e8e6defbd864d58cc1ae @@ -27,12 +25,6 @@ importers: .: devDependencies: - '@stryker-mutator/core': - specifier: 10.0.0 - version: 10.0.0(@types/node@26.6.5) - '@stryker-mutator/vitest-runner': - specifier: 10.0.0 - version: 10.0.0(patch_hash=c5d635178da5a48e07051030a6d2eb3f33f4b31a71f4232c05f099e8e90f3dc2)(@stryker-mutator/core@10.0.0(@types/node@26.6.5))(vitest@5.0.5) '@stylistic/eslint-plugin': specifier: ^5.10.0 version: 5.10.0(eslint@10.13.0(jiti@2.7.0)(supports-color@8.1.1)) @@ -127,211 +119,26 @@ packages: resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/code-frame@8.0.6': - resolution: {integrity: sha512-uMHhvmDmwFiLuiozaoRYTZHqMFuu3fem/X9JY78lohAuLoh8LSGGC8JqUzo2cVuBsBxkjMZNk56CE7ock8Xxkw==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/compat-data@8.0.5': - resolution: {integrity: sha512-YLsYoQMvL8l8WrGpN3Zj7O1wK5LEBN+cQtux7BcuHyxIXve724XG+zuJ1n3U1cUweRtTzQOA4IHbuQw3N34SZw==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/core@8.0.6': - resolution: {integrity: sha512-5zwYt1V4ji3mXKKRIAkohSJ29WepxNwxQi+7y7P5AcVPh1dcxnZBU2cfxHnPwS+u9+lZnXPsv30TQaF2xg+Tfg==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/generator@8.0.6': - resolution: {integrity: sha512-/pcanjdRsonCexCuxgGD8fKnBLLzk2i9uM4kmcmGyyev2R5YDs+rafMYZ89RvaGY1mW8T7C5au0TyYaEeHBGng==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/helper-annotate-as-pure@8.0.0': - resolution: {integrity: sha512-NSpMkMsvvZqzThJ0p1B02cbtA2ObEyfBvq950bmNkyxsxvcxwhvvCB036rKhlEnuBBo30bOrk13u3FzlKSoRrw==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/helper-compilation-targets@8.0.6': - resolution: {integrity: sha512-HTrtZ4+iA0+kzdbCgvdSk1U4pEl3BvpGnlUbualCGNbrVhhQvhgBzurTUmqpWyvyHbWYWaIfdx2mOlL9LJjsew==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/helper-create-class-features-plugin@8.0.6': - resolution: {integrity: sha512-Hy7wG2Pk1LnAkFMq0CbBk789XMTYVzYGxR7tKgk+TOpZckQRME3Tdou4mMT/8DFjJFxFZ8R6UsS4DR/duBKlVA==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/helper-globals@8.0.6': - resolution: {integrity: sha512-OdnA/N52LhzFpeUuVz5YGuSWjc7TPHiFmVYZbPlSgExocO2GwbxVpSni9MVs5wwW+wZ4kPuwBEBN9pIPDYz1mA==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/helper-member-expression-to-functions@8.0.5': - resolution: {integrity: sha512-GLe05QD98BkNFTkjaqeqF9QSRoHLKrrB4tpoplyQuuPrQJ72rtmkM4wvqJLX/sjZPqkbK5MUYSsuUTqdJoOVjA==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/helper-module-imports@8.0.0': - resolution: {integrity: sha512-NZ7mSS93o4ndX4KrbD7W8Sf3QT8Qe24PrnFyUcuOPDzK6faqDFKjY9RG7he7+I7FdiQ4llpnosFqzrXa+Vy3Ew==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/helper-module-transforms@8.0.6': - resolution: {integrity: sha512-YUi+3X0cb0v97xKhuqkLdrwQtP6XXv1eVbhLRCFyMwG481UskbMQk4mjH7K/Jg3oJ1KLskvFwwq4kF/QnABkWQ==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/helper-optimise-call-expression@8.0.0': - resolution: {integrity: sha512-3W6satvtPuCUkUx63S2jMoW9EQNYkADgs1HTfufmL7gCmAulHMKupA/12WNz4A0GMMFn/YnWWwqOT9IZrJHQjg==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/helper-plugin-utils@8.0.1': - resolution: {integrity: sha512-3PKFgjTyPlhFhorfP+SjKQxLViIL++zWjFOO4hGriYU+Bsm983DxEM1JmDRJVWXV0O9npu+xXRqz7Pbd3mh70g==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/helper-replace-supers@8.0.1': - resolution: {integrity: sha512-B1SZADIcy3tmH8CmWvj4SHi/oAPom4UL3uknTc2QRNsPVLFk/sPnZvQL/8kj7Y5omvjMqie0vklvs6XM4OLW5Q==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/helper-skip-transparent-expression-wrappers@8.0.0': - resolution: {integrity: sha512-xmCA9kP3IhySsqhzwIdWGlDN/1A4cCKNBO/uwZx/3YzmDoMePwno2Q5/Bq0q+tYaKbeF940YiKV/kaW8Mzvpjw==} - engines: {node: ^22.18.0 || >=24.11.0} - '@babel/helper-string-parser@7.29.7': resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@8.0.6': - resolution: {integrity: sha512-+6HYEBnsDRZHJtUTAEfMQd0zMDqdFHS7C+5vAsEZqBUr3vEMWOWlHJ0Jz1gS8jJIlCvLsuA6ivmeoqzH936YcA==} - engines: {node: ^22.18.0 || >=24.11.0} - '@babel/helper-validator-identifier@7.29.7': resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@8.0.6': - resolution: {integrity: sha512-HYx0YmuchRxRSpnjvcNffnPS8DCauKNmnumIuHG3jnQAVewRA7kfJGwF13ayEpSZs7s4R/oBH4eppuXcAQd5JQ==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/helper-validator-option@8.0.0': - resolution: {integrity: sha512-U4Dybxh4WESWHt5XhBeExi4DrY0/DNK1aHpQbsrQXCUbFHuMweT0TpLEWKvaraV2Y6fS+ZXunsZ8zIuZIgvF2Q==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/helpers@8.0.5': - resolution: {integrity: sha512-fQtPOXjYOYv85PIdwotp2TJGVYOycX0PQq+l844fFAxOULtBy8BVF35GyeueX0r4KvDthqPH5xAI1clQPk/2uA==} - engines: {node: ^22.18.0 || >=24.11.0} - '@babel/parser@7.29.8': resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@8.0.6': - resolution: {integrity: sha512-LpGDIYJAzc3Y3PT9x+FxBrGYu2PlWxLmyN7SwPTzaX0LSwEmFJBsRnPBqmaXF2r1v+Zhz6lNiEJ+7yKtM5+Ugg==} - engines: {node: ^22.18.0 || >=24.11.0} - hasBin: true - - '@babel/plugin-proposal-decorators@8.0.2': - resolution: {integrity: sha512-+C6O6KKXU7BBq1GNaIkFJxrALUVGRcr+WeWm4OcuRl3h+l/CmNfcTLMrT2Lm3uvGBimBH/8pEBRrXJFLoO67Gg==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/plugin-syntax-decorators@8.0.1': - resolution: {integrity: sha512-NI+0S/6MvR6GlcQFwjDZ+WIc2qvG6TXN534lYs9llNldwW4b7Dh6KTtk030FA0xWdYGs4t1lWo+OEWN8wGB+Nw==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/plugin-syntax-jsx@8.0.1': - resolution: {integrity: sha512-n0jtCOxEovhU7METqSQjcZO9pX53nu9uNIjMS+hEt+Nt9jA7oOZoBIgbCxhhASmF6T6rPDGge5UAvh6Z4eFz/g==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/plugin-syntax-typescript@8.0.3': - resolution: {integrity: sha512-jmTPwps7oSQSZaV1SxkQ3C12UWyufGysGc5OzDpZzvPAIX4mO7dJT3hoqkWVrSImvkcMiknir1iLN1SNV/CZzg==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/plugin-transform-destructuring@8.0.5': - resolution: {integrity: sha512-evjxc5fGvpXG2WMGSalpX8IJZVumLIDgk5r5eRhvXRDqFX/GPWq1BeRfJalPCcwJfrR5A/wvegUhx9W5Nr7/mg==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/plugin-transform-explicit-resource-management@8.0.5': - resolution: {integrity: sha512-Vr20jk/ZxRGu30o0jYvcKl2Pf0tiyr8H9q2ZGxYD6yjOpv9DdP6//I85q0cSOdADZhsu/ZZoApjGVCfl4xnVJw==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/plugin-transform-modules-commonjs@8.0.1': - resolution: {integrity: sha512-PMuzulWrrzFNmY3lXSk/tV9NRb7y0eZZLJY4UEo2TKszroxvUZHAPPi+T9FDyrQhod+TQA+t+8/QYaaMpiEuhA==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/plugin-transform-react-display-name@8.0.1': - resolution: {integrity: sha512-soLishXlkyu6jcICPyO3HEP7A3GCzKEnn7XfvYrImuWEOwFAz93qShmWSYPf5ww0ZkO4By0zsN2bVIDF54fSdA==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/plugin-transform-react-jsx-development@8.0.1': - resolution: {integrity: sha512-Hb+HUZpV9KFHjm+F+P3aLDMi8QXU9l3ROCQv20z18Me2sGyW5nNNR5YTevNlgHvCpFek3BnAwhDGq/BRndXViw==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/plugin-transform-react-jsx@8.0.1': - resolution: {integrity: sha512-NgkoF7Uq+30TmOPDdNUimT0Nta02uVjqJRFNlVWKrbOCu/CkzfHa4aMnIs0lMpkMmZmWA1e42Va+F04i/pY1zw==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/plugin-transform-react-pure-annotations@8.0.1': - resolution: {integrity: sha512-7/8UwU8hoPBurXa9tUiTTC8aACTRy5tCqLUtqikHp2eGiWoEB57AduOdbQ71OOMTEvawKrGhv3WfzkDpI+/oSg==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/plugin-transform-typescript@8.0.6': - resolution: {integrity: sha512-WF3yRlQtClzScvQbWct00ix63+w3DPiyU0WmCBU4YqK539n3VvJFElElpevoD8wfu6953CbiNoUZBi2B7/5jXw==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/preset-react@8.0.1': - resolution: {integrity: sha512-jrFuPp/pTddFZbtmWhdLNAYc6UMcpboeUPnw0BBrm4nOmcAko/1TRcFi1PzWCeOFRU+VaSiKmat87W1HvR7mIg==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - - '@babel/preset-typescript@8.0.1': - resolution: {integrity: sha512-qrPhQIN1NLrPmzgazF9XKQqXrOcp/WJly+K+6ReFonn24FZqRJO7clxOJo6Ni75L+2vAqI3cHVU2OJLBxoPp5A==} - engines: {node: ^22.18.0 || >=24.11.0} - peerDependencies: - '@babel/core': ^8.0.0 - '@babel/runtime@8.0.7': resolution: {integrity: sha512-k0hagDDq/6w4v+0Sp4wFvIz/yswH5O7Va6aRTnD7N62Tnborp4X+YB+H3XUcWVSR4aE47WPEXiIIZchBs0GmYg==} - '@babel/template@8.0.0': - resolution: {integrity: sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==} - engines: {node: ^22.18.0 || >=24.11.0} - - '@babel/traverse@8.0.6': - resolution: {integrity: sha512-ilYV+qLStGzSKLipJlETdvdtpK3rAuwfCmCoGKv15MU4EoeIuLkespSNoNLFGOPSciEHx9TLWtN5mv0fz5w5mQ==} - engines: {node: ^22.18.0 || >=24.11.0} - '@babel/types@7.29.8': resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} - '@babel/types@8.0.6': - resolution: {integrity: sha512-c+xgSWboV2pdwXP67BUWDVRHi2BO5Q3KwxyFVs7taVTY+fsK47/L51ZXQoV9rozHJDNHvJ4v4WEsI/IlxV2l2A==} - engines: {node: ^22.18.0 || >=24.11.0} - '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} @@ -588,10 +395,6 @@ packages: resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} engines: {node: '>=18'} - '@inquirer/ansi@2.0.8': - resolution: {integrity: sha512-WpQM+Ti6Z40EFwwt+uL2p4UabT+W179zHp6HhLVOzfbwnVn05IPO/eXIZXGNqcT1jbQ15SujNLzQ39k4QPPxBQ==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - '@inquirer/checkbox@4.3.2': resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} engines: {node: '>=18'} @@ -601,15 +404,6 @@ packages: '@types/node': optional: true - '@inquirer/checkbox@5.2.5': - resolution: {integrity: sha512-bRt8J8m+Fot9CXv+zNQGXUq2ET0MggR1fPz7v6edN6MFYmsbfGnMmkmWZJEegMKqrAC8ej/o1sqisHZXZJMAfQ==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/confirm@5.1.21': resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} engines: {node: '>=18'} @@ -619,15 +413,6 @@ packages: '@types/node': optional: true - '@inquirer/confirm@6.3.2': - resolution: {integrity: sha512-Xvr/0HggjddPtGppuqVmxhTw+Hr8PvsZ/k0HmOEaAqQEt80OITNkFWnsdNmyT0/eM4Ab+iJLx2R8rctlEyfSVg==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/core@10.3.2': resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} engines: {node: '>=18'} @@ -637,15 +422,6 @@ packages: '@types/node': optional: true - '@inquirer/core@12.0.3': - resolution: {integrity: sha512-wsSy0sznmXwkty+2PzZwx00Cazc/E0r0B7mAzdGROz2Ct+DFZXaK7WDjGZvgjRldxH5ZhFVfF2lgkYrqgOw2KA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/editor@4.2.23': resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} engines: {node: '>=18'} @@ -655,15 +431,6 @@ packages: '@types/node': optional: true - '@inquirer/editor@5.3.3': - resolution: {integrity: sha512-YsKkS2q63IiLtaDK/9nqzdComN97SDQrmKiyNggN+ceP4ty+Z6VwyTz3FpjeUWeW1Efss2xHFKCC9sx7hnrsxg==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/expand@4.0.23': resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} engines: {node: '>=18'} @@ -673,15 +440,6 @@ packages: '@types/node': optional: true - '@inquirer/expand@5.1.5': - resolution: {integrity: sha512-uHuXLmXW+TtIfT/9vSBotypAkqn1n34Ul+CLGPos/xANyO4Ff5xZzkYhbKR4NEcfVK4a9mHQOpwVZzluSHFRGw==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/external-editor@1.0.3': resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} engines: {node: '>=18'} @@ -691,23 +449,10 @@ packages: '@types/node': optional: true - '@inquirer/external-editor@3.0.5': - resolution: {integrity: sha512-f3QQJRIX5ZEneBHNUIuPjmbdzHnmRFJA8r2dkcb8q+OM5Uv5KtnuAttQumnrjcBVBM3mcTX1CkmtAkU58VRZxg==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/figures@1.0.15': resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} engines: {node: '>=18'} - '@inquirer/figures@2.0.9': - resolution: {integrity: sha512-EAWgUTGQ/Umgga51dE3B2PUHbufuXarDfg86uVgoSgNHNNQnyFKcOrQLWVqYMghuSyHh8+2HUH0Js9cTC1WAdg==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - '@inquirer/input@4.3.1': resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} engines: {node: '>=18'} @@ -717,15 +462,6 @@ packages: '@types/node': optional: true - '@inquirer/input@5.1.6': - resolution: {integrity: sha512-HtcJhB2QFVXbLuJ5S3syhNbTUVxYvwqV4VRBDkQceBloC9bmTViUoRFP5PbSaDZb3HzfPmpuU/gG4ybVBz4FHA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/number@3.0.23': resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} engines: {node: '>=18'} @@ -735,15 +471,6 @@ packages: '@types/node': optional: true - '@inquirer/number@4.2.3': - resolution: {integrity: sha512-6Yuwh1NGSbu1Lo4N1EWjXs1jKRntLg/ZCwhmeorEHde90v1XxAozdbd4Iu30eOQLW+6h1hp2O9ujNfLSbTPJnA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/password@4.0.23': resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} engines: {node: '>=18'} @@ -753,15 +480,6 @@ packages: '@types/node': optional: true - '@inquirer/password@5.2.2': - resolution: {integrity: sha512-W9zYdyzogK+6110mqwaSJWCBu2yA5Q/OfnGSjjZB1bNpHlmUozXxTl0+QOZBNeVd6Qo81/qT75gW05gLAtITxw==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/prompts@7.10.1': resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} engines: {node: '>=18'} @@ -771,15 +489,6 @@ packages: '@types/node': optional: true - '@inquirer/prompts@8.7.2': - resolution: {integrity: sha512-QoRB4wFIjgH5iOhSjoIKMkTvSHDuV+O3OITlIqAYO0oK5x364GJILXiMBvlPiE+klg7Xx9tq5XVqQHcGUDYYPA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/rawlist@4.1.11': resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} engines: {node: '>=18'} @@ -789,15 +498,6 @@ packages: '@types/node': optional: true - '@inquirer/rawlist@5.3.5': - resolution: {integrity: sha512-1oHky1ONfCOwNrnkQGDE1oaSij/3fI6HFMSf2H/WsGO2lEyDX9My82iggITSy9ddSZ8yk8j9v41OI0fVoSIoaA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/search@3.2.2': resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} engines: {node: '>=18'} @@ -807,15 +507,6 @@ packages: '@types/node': optional: true - '@inquirer/search@4.3.3': - resolution: {integrity: sha512-fyuIU1Nbpvwlikjg3gXwJFDI11+EFjqQ7P+iByfmivIKQ1vmaykNrD/vy5unHuUqUpsOsnvJ25//tPF7E/RBRA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/select@4.4.2': resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} engines: {node: '>=18'} @@ -825,15 +516,6 @@ packages: '@types/node': optional: true - '@inquirer/select@5.2.5': - resolution: {integrity: sha512-9kc15hr8r/kI+3DO/xLog5nOzTz1jqsHXa6JBFzmQKhkoJ8Slda1I1L/uD8ZSZ9tF1yp79wwXe7mclvX1rqR2Q==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/type@3.0.10': resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} engines: {node: '>=18'} @@ -843,15 +525,6 @@ packages: '@types/node': optional: true - '@inquirer/type@4.1.1': - resolution: {integrity: sha512-yJoHYrMnxIsJZCY+0Vb66Dy3he3kL3e2wOBKhoSwWWAzZAY82emlxwgprCtp6yRixvNRNq9ztfRWQYPNr3Go7A==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -880,9 +553,6 @@ packages: resolution: {integrity: sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jridgewell/gen-mapping@0.4.0-beta.0': - resolution: {integrity: sha512-JdGNkbE4GlNPYQhM0L95fBQr7ctLZJ276QXQLTad4t1oSdnnCI3fDq9DW3BqYAWv8Wc3+HS+4Gsii1oPMCfz1w==} - '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -1052,29 +722,6 @@ packages: resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} - '@stryker-mutator/api@10.0.0': - resolution: {integrity: sha512-ZtAJ0ZT3MVRCWJTBE2h90XB/6E+4lifHYtcTyNG6nU2nLekPgTo4gD5esjX6Okxo1b/JB4jJzyxYB54fwKAoJw==} - engines: {node: '>=22.0.0'} - - '@stryker-mutator/core@10.0.0': - resolution: {integrity: sha512-ZvMsRyaXQQ5e6Thcid9pkuODv6Fn9E3nrBQJUap+hcJuGJ4unm26afo3m6YKSjn8kinyxJ/3TXf0cTWRDaTxVw==} - engines: {node: '>=22.0.0'} - hasBin: true - - '@stryker-mutator/instrumenter@10.0.0': - resolution: {integrity: sha512-B7Wmn1KlEWyFeOz6D6oGvQGRfi5Xw3VemG6dEKvFQp4qLvxD9Mf4kcZghfxffgnYwXd3bFgqXsJ+ZGlhdfIOrQ==} - engines: {node: '>=22.0.0'} - - '@stryker-mutator/util@10.0.0': - resolution: {integrity: sha512-LzOpHiJaCp2ABQgnPMlrQQcsK43bd5Vo/2FGL78aN62yDoeRQ+4j3tzeuXxK5OAHdC3fUz6TDoy4IsoAuLAd3w==} - - '@stryker-mutator/vitest-runner@10.0.0': - resolution: {integrity: sha512-SHK2/vfvRUpiz7jXPnQMBnr6zLdm69DK03Mo5mPhaZWcRSygrKUqYsPqWsXsK+5ySHzlMTfCyFK5NQ/X9sJFFw==} - engines: {node: '>=22.0.0'} - peerDependencies: - '@stryker-mutator/core': 10.0.0 - vitest: '>=2.0.0' - '@stylistic/eslint-plugin@5.10.0': resolution: {integrity: sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1170,9 +817,6 @@ packages: '@types/filewriter@0.0.33': resolution: {integrity: sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==} - '@types/gensync@1.0.5': - resolution: {integrity: sha512-MbsRCT7mTikHwKZ0X+LVUTLRrZZRLipTuXEO9qOYO+zmjMVk81axyClMROf6uoPD9MRVu46bx8zoR0Ad9q3NAg==} - '@types/har-format@1.2.16': resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==} @@ -1185,9 +829,6 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - '@types/jsesc@2.5.1': - resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} - '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -1547,10 +1188,6 @@ packages: ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - angular-html-parser@10.11.0: - resolution: {integrity: sha512-3vERzJ65UFDr3C7uozLJwsNcQS3FS784dSh583oDgDTTZMgXe3/pdyXgKndxiP5R2lvYRfW6gSl145Hnyf2OFA==} - engines: {node: '>= 14'} - ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -1672,11 +1309,6 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.11.26: - resolution: {integrity: sha512-GLQdD3y6UF8iVuMJl5fHgE4jdn/ua7n+toKfLgNlg3BqQtOZjpy68T8Tup8/wGWZCDlm7KMg7tPb4MPn7oN0TQ==} - engines: {node: '>=6.0.0'} - hasBin: true - bcp-47-match@2.0.3: resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} @@ -1700,11 +1332,6 @@ packages: browser-stdout@1.3.1: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - browserslist@4.29.3: - resolution: {integrity: sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - buffer-crc32@1.0.0: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} engines: {node: '>=8.0.0'} @@ -1725,14 +1352,6 @@ packages: cacheable@2.5.0: resolution: {integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==} - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1741,9 +1360,6 @@ packages: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} - caniuse-lite@1.0.30001814: - resolution: {integrity: sha512-/Uaf1lAzr59XcMpW0o96WoEfr+VXK2OX4U9AgFoiSHsVJ4HppnIFUjtYzsyDH2+tgANaQb2/oxYGwCPapN1FpA==} - chai@6.3.0: resolution: {integrity: sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==} engines: {node: '>=18'} @@ -1942,16 +1558,10 @@ packages: resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} engines: {node: '>=12'} - des.js@1.1.0: - resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - diff-match-patch@1.0.5: - resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} - diff@8.0.4: resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} engines: {node: '>=0.3.1'} @@ -1981,10 +1591,6 @@ packages: resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -2020,10 +1626,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - empathic@2.1.0: - resolution: {integrity: sha512-AnfC1ATldl49/cvZdLPDjBfrRNwbDO05aibiOtzQu3qtlbJtomNLhF30HEtn/7iBz50dlMECqATo3fG0LrdEgw==} - engines: {node: '>=14'} - encoding-sniffer@0.2.1: resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} @@ -2042,21 +1644,9 @@ packages: error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - es-module-lexer@2.3.2: resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} - es-object-atoms@1.1.2: - resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} - engines: {node: '>= 0.4'} - es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} @@ -2218,18 +1808,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-string-truncated-width@3.0.3: - resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} - - fast-string-width@3.0.2: - resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - fast-uri@3.1.8: resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==} - fast-wrap-ansi@0.2.2: - resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -2284,10 +1865,6 @@ packages: flatted@3.4.4: resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} - flru@1.0.2: - resolution: {integrity: sha512-kWyh8ADvHBFz6ua5xYOPnUroZTT/bwWfrCeL0Wj1dzG4/YOmOcfJ99W8dOVyyynJN35rZ9aCOtHChqQovV7yog==} - engines: {node: '>=6'} - foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} @@ -2301,9 +1878,6 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - fuse.js@7.5.0: resolution: {integrity: sha512-sQtrEfA+ez/3G0cCZecF70oqpCRttCexYUG4mUrtWL49ULUzUyxokt5kyqwtKzj1270RaKih+hcP3qLcumccow==} engines: {node: '>=10'} @@ -2324,10 +1898,6 @@ packages: peerDependencies: '@wdio/logger': ^9.18.0 || ^10.0.0 - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -2336,18 +1906,10 @@ packages: resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - get-port@7.2.0: resolution: {integrity: sha512-afP4W205ONCuMoPBqcR6PSXnzX35KTcJygfJfcp+QY+uwm3p20p1YczWXhlICIzGMCxYBQcySEcOgsJcrkyobg==} engines: {node: '>=16'} - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - get-stream@9.0.1: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} @@ -2380,10 +1942,6 @@ packages: resolution: {integrity: sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==} engines: {node: '>=18'} - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - graceful-fs@4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} @@ -2397,18 +1955,10 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - hashery@1.5.1: resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==} engines: {node: '>=20'} - hasown@2.0.4: - resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} - engines: {node: '>= 0.4'} - hls.js@1.7.3: resolution: {integrity: sha512-MsPlx6yVW4Qv4C7mEVou4/gk/5cN2dVxOTnrNjPSmyH2f0Ln+/UkG10Ax1PE6OvrmTVPKgQYozTtBaPOuCzq7A==} @@ -2642,9 +2192,6 @@ packages: jose@5.9.6: resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} - js-md4@0.3.2: - resolution: {integrity: sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==} - js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} @@ -2659,11 +2206,6 @@ packages: resolution: {integrity: sha512-paNr4LFIFPjeeSmwNYdrb8FafLLG/Cr2Af3GjbsHJ5CxIjH4r0c2emlmRdAtpPAieP1gRVzk6buBbVP5gBMGAg==} hasBin: true - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -2674,9 +2216,6 @@ packages: resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - json-rpc-2.0@1.8.1: - resolution: {integrity: sha512-BmN42JKn6FI36pcMMzHCXQhpKNEfbeqgSIcUYHKnifq0/4Ey6PDinovwUOgajT7NsgUtpWdDXaCWlpI4LHXN3g==} - json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -2686,11 +2225,6 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - jsonfile@6.2.1: resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} @@ -2836,9 +2370,6 @@ packages: lodash.flattendeep@4.4.0: resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} - lodash.groupby@4.6.0: - resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==} - lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} @@ -2898,19 +2429,12 @@ packages: marky@1.3.0: resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} mediabunny@1.61.6: resolution: {integrity: sha512-VHEZ53/7jGl4dQ+uOdndsZufFYwEUFWv9UXgvrGun3OapyzoqI9iaPOD7z3xxY/nAttLZBNwswgJzMtGJAquOQ==} - minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - minimatch@10.2.6: resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} engines: {node: 18 || 20 || >=22} @@ -2956,27 +2480,10 @@ packages: resolution: {integrity: sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - mutation-server-protocol@0.4.1: - resolution: {integrity: sha512-SBGK0j8hLDne7bktgThKI8kGvGTx3rY3LAeQTmOKZ5bVnL/7TorLMvcVF7dIPJCu5RNUWhkkuF53kurygYVt3g==} - engines: {node: '>=18'} - - mutation-testing-elements@3.8.4: - resolution: {integrity: sha512-5CF1SNa7at5ZH33vEr+21wNebTSrtNIVvnzaUlxortHajOrIPaSLczIWvg6sI/fsExekQ7jookwf2cHftkckqQ==} - - mutation-testing-metrics@3.8.4: - resolution: {integrity: sha512-DZcmndJBH6nrNs3tpiB3OcMVq9KkG2cHCpJSnDxSxPwi9qrafRmoec40xjhkbzOoX1n7/4UkDqg5tIj4A6nvCw==} - - mutation-testing-report-schema@3.8.4: - resolution: {integrity: sha512-s4G71R6Lt/PpZ0cqeglIcgyBdzLM8E+SeCHZAPg1wkSsPtRBa4XfPzAozYKdiJk/TLbNEEb7En9t0/bveuPuxA==} - mute-stream@2.0.0: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} - mute-stream@3.0.0: - resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} - engines: {node: ^20.17.0 || >=22.9.0} - nanoid@3.3.20: resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -2985,10 +2492,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - node-releases@2.0.57: - resolution: {integrity: sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==} - engines: {node: '>=18'} - normalize-package-data@6.0.2: resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} engines: {node: ^16.14.0 || >=18.0.0} @@ -3012,10 +2515,6 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} - obug@2.2.1: - resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} - engines: {node: '>=12.20.0'} - obug@3.0.0: resolution: {integrity: sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==} engines: {node: '>=12.20.0'} @@ -3171,10 +2670,6 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - promise-toolbox@0.21.0: resolution: {integrity: sha512-NV8aTmpwrZv+Iys54sSFOBx3tuVaOBvvrft5PNppnxy9xpU/akHbaWIril22AB22zaPgrgwKdD0KsrM0ptUtpg==} engines: {node: '>=6'} @@ -3197,10 +2692,6 @@ packages: resolution: {integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==} engines: {node: '>=20'} - qs@6.16.0: - resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==} - engines: {node: '>=0.6'} - query-selector-shadow-dom@1.0.1: resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} @@ -3350,22 +2841,6 @@ packages: resolution: {integrity: sha512-PcByqNyT/38F2kDNi006HAMRJaULuBzq/FOsw3qdZvX/GA9W/jamDaRskgHjubHiftXK5sIFxLNkvrXUwcof6Q==} engines: {node: '>= 0.4'} - side-channel-list@1.0.1: - resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.1: - resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} - engines: {node: '>= 0.4'} - signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -3391,10 +2866,6 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} - spacetrim@0.11.59: resolution: {integrity: sha512-lLYsktklSRKprreOm7NXReW8YiX2VBjbgmXYEziOoGf/qsJqAEACaDvoTtUOycwjpaSh+bT8eu0KrJn7UNxiCg==} @@ -3537,10 +3008,6 @@ packages: resolution: {integrity: sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==} engines: {node: '>=14.14'} - tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -3549,10 +3016,6 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - tunnel@0.0.6: - resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} - engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -3569,22 +3032,11 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} - typed-inject@5.0.0: - resolution: {integrity: sha512-0Ql2ORqBORLMdAW89TQKZsb1PQkFGImFfVmncXWe7a+AA3+7dh7Se9exxZowH4kbnlvKEFkMxUYdHUpjYWFJaA==} - engines: {node: '>=18'} - - typed-rest-client@2.3.1: - resolution: {integrity: sha512-k4kX5Up6qA68D0Cby2AK+6+vM5k3qTxe+/3FqhnHRExjY5cfbOnzjQZbP/LXleF8hVoDvDqxlgk9KK83HoBZlQ==} - engines: {node: '>= 16.0.0'} - typescript@7.0.2: resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} engines: {node: '>=16.20.0'} hasBin: true - underscore@1.13.8: - resolution: {integrity: sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==} - undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -3611,12 +3063,6 @@ packages: resolution: {integrity: sha512-YAsrLMIlhfSCm9rga5TZsJ1mXgahs7N0qOTokzU8mFz35hUrYMvVkaEPefI3rEb/vkAWAOj1Km/qdije9RC1kQ==} engines: {node: '>=20'} - update-browserslist-db@1.3.3: - resolution: {integrity: sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - update-notifier@7.3.1: resolution: {integrity: sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA==} engines: {node: '>=18'} @@ -3637,10 +3083,6 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - verkit@0.3.2: - resolution: {integrity: sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg==} - engines: {node: '>=18.12.0'} - vite@8.3.4: resolution: {integrity: sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3737,9 +3179,6 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - weapon-regex@2.0.5: - resolution: {integrity: sha512-BJZkSdtcae9Wb8+hKNtAqR+Q61EMOAuQnpCCHKwT50K7fIWg7/2/RnbKR27YB+sMcYxYLUVj+Asm5Y2XhD8mZg==} - web-ext@10.8.0: resolution: {integrity: sha512-UdZJkdZZ9TTqDUDZLf1Tb9MCFQsi2P7FmHGx2e00VB+1U9iJPA1WUUHUtdjh2m7Cnh6su27wivhmEkaSkcl2+g==} engines: {node: '>=20.0.0', npm: '>=8.0.0'} @@ -3895,9 +3334,6 @@ packages: resolution: {integrity: sha512-dSvYKdvLsAHCDqPOhIwk/q5CvuWtTB3Dgpoe0uVEFjTzIOAmsQpprX25InCvrvJsirEbu1OHyy67n/kAj1Sw/w==} engines: {node: '>=18'} - zod@4.6.5: - resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==} - snapshots: '@babel/code-frame@7.29.7': @@ -3906,245 +3342,21 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/code-frame@8.0.6': - dependencies: - '@babel/helper-validator-identifier': 8.0.6 - js-tokens: 10.0.0 - - '@babel/compat-data@8.0.5': {} - - '@babel/core@8.0.6': - dependencies: - '@babel/code-frame': 8.0.6 - '@babel/generator': 8.0.6 - '@babel/helper-compilation-targets': 8.0.6 - '@babel/helpers': 8.0.5 - '@babel/parser': 8.0.6 - '@babel/template': 8.0.0 - '@babel/traverse': 8.0.6 - '@babel/types': 8.0.6 - '@types/gensync': 1.0.5 - convert-source-map: 2.0.0 - empathic: 2.1.0 - gensync: 1.0.0-beta.2 - import-meta-resolve: 4.2.0 - json5: 2.2.3 - obug: 2.2.1 - verkit: 0.3.2 - - '@babel/generator@8.0.6': - dependencies: - '@babel/parser': 8.0.6 - '@babel/types': 8.0.6 - '@jridgewell/gen-mapping': 0.4.0-beta.0 - '@jridgewell/trace-mapping': 0.3.31 - '@types/jsesc': 2.5.1 - jsesc: 3.1.0 - - '@babel/helper-annotate-as-pure@8.0.0': - dependencies: - '@babel/types': 8.0.6 - - '@babel/helper-compilation-targets@8.0.6': - dependencies: - '@babel/compat-data': 8.0.5 - '@babel/helper-validator-option': 8.0.0 - browserslist: 4.29.3 - flru: 1.0.2 - verkit: 0.3.2 - - '@babel/helper-create-class-features-plugin@8.0.6(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-annotate-as-pure': 8.0.0 - '@babel/helper-member-expression-to-functions': 8.0.5 - '@babel/helper-optimise-call-expression': 8.0.0 - '@babel/helper-replace-supers': 8.0.1(@babel/core@8.0.6) - '@babel/helper-skip-transparent-expression-wrappers': 8.0.0 - '@babel/traverse': 8.0.6 - verkit: 0.3.2 - - '@babel/helper-globals@8.0.6': {} - - '@babel/helper-member-expression-to-functions@8.0.5': - dependencies: - '@babel/traverse': 8.0.6 - '@babel/types': 8.0.6 - - '@babel/helper-module-imports@8.0.0': - dependencies: - '@babel/traverse': 8.0.6 - '@babel/types': 8.0.6 - - '@babel/helper-module-transforms@8.0.6(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-module-imports': 8.0.0 - '@babel/helper-validator-identifier': 8.0.6 - '@babel/traverse': 8.0.6 - - '@babel/helper-optimise-call-expression@8.0.0': - dependencies: - '@babel/types': 8.0.6 - - '@babel/helper-plugin-utils@8.0.1(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - - '@babel/helper-replace-supers@8.0.1(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-member-expression-to-functions': 8.0.5 - '@babel/helper-optimise-call-expression': 8.0.0 - '@babel/traverse': 8.0.6 - - '@babel/helper-skip-transparent-expression-wrappers@8.0.0': - dependencies: - '@babel/traverse': 8.0.6 - '@babel/types': 8.0.6 - '@babel/helper-string-parser@7.29.7': {} - '@babel/helper-string-parser@8.0.6': {} - '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-identifier@8.0.6': {} - - '@babel/helper-validator-option@8.0.0': {} - - '@babel/helpers@8.0.5': - dependencies: - '@babel/template': 8.0.0 - '@babel/types': 8.0.6 - '@babel/parser@7.29.8': dependencies: '@babel/types': 7.29.8 - '@babel/parser@8.0.6': - dependencies: - '@babel/types': 8.0.6 - - '@babel/plugin-proposal-decorators@8.0.2(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-create-class-features-plugin': 8.0.6(@babel/core@8.0.6) - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - '@babel/plugin-syntax-decorators': 8.0.1(@babel/core@8.0.6) - - '@babel/plugin-syntax-decorators@8.0.1(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - - '@babel/plugin-syntax-jsx@8.0.1(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - - '@babel/plugin-syntax-typescript@8.0.3(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - - '@babel/plugin-transform-destructuring@8.0.5(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - - '@babel/plugin-transform-explicit-resource-management@8.0.5(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - '@babel/plugin-transform-destructuring': 8.0.5(@babel/core@8.0.6) - - '@babel/plugin-transform-modules-commonjs@8.0.1(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-module-transforms': 8.0.6(@babel/core@8.0.6) - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - - '@babel/plugin-transform-react-display-name@8.0.1(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - - '@babel/plugin-transform-react-jsx-development@8.0.1(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/plugin-transform-react-jsx': 8.0.1(@babel/core@8.0.6) - - '@babel/plugin-transform-react-jsx@8.0.1(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-annotate-as-pure': 8.0.0 - '@babel/helper-module-imports': 8.0.0 - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - '@babel/plugin-syntax-jsx': 8.0.1(@babel/core@8.0.6) - '@babel/types': 8.0.6 - - '@babel/plugin-transform-react-pure-annotations@8.0.1(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-annotate-as-pure': 8.0.0 - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - - '@babel/plugin-transform-typescript@8.0.6(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-annotate-as-pure': 8.0.0 - '@babel/helper-create-class-features-plugin': 8.0.6(@babel/core@8.0.6) - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - '@babel/helper-skip-transparent-expression-wrappers': 8.0.0 - '@babel/plugin-syntax-typescript': 8.0.3(@babel/core@8.0.6) - - '@babel/preset-react@8.0.1(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - '@babel/helper-validator-option': 8.0.0 - '@babel/plugin-transform-react-display-name': 8.0.1(@babel/core@8.0.6) - '@babel/plugin-transform-react-jsx': 8.0.1(@babel/core@8.0.6) - '@babel/plugin-transform-react-jsx-development': 8.0.1(@babel/core@8.0.6) - '@babel/plugin-transform-react-pure-annotations': 8.0.1(@babel/core@8.0.6) - - '@babel/preset-typescript@8.0.1(@babel/core@8.0.6)': - dependencies: - '@babel/core': 8.0.6 - '@babel/helper-plugin-utils': 8.0.1(@babel/core@8.0.6) - '@babel/helper-validator-option': 8.0.0 - '@babel/plugin-transform-modules-commonjs': 8.0.1(@babel/core@8.0.6) - '@babel/plugin-transform-typescript': 8.0.6(@babel/core@8.0.6) - '@babel/runtime@8.0.7': {} - '@babel/template@8.0.0': - dependencies: - '@babel/code-frame': 8.0.6 - '@babel/parser': 8.0.6 - '@babel/types': 8.0.6 - - '@babel/traverse@8.0.6': - dependencies: - '@babel/code-frame': 8.0.6 - '@babel/generator': 8.0.6 - '@babel/helper-globals': 8.0.6 - '@babel/parser': 8.0.6 - '@babel/template': 8.0.0 - '@babel/types': 8.0.6 - obug: 2.2.1 - '@babel/types@7.29.8': dependencies: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@babel/types@8.0.6': - dependencies: - '@babel/helper-string-parser': 8.0.6 - '@babel/helper-validator-identifier': 8.0.6 - '@bcoe/v8-coverage@1.0.2': {} '@cacheable/memory@2.2.0': @@ -4333,8 +3545,6 @@ snapshots: '@inquirer/ansi@1.0.2': {} - '@inquirer/ansi@2.0.8': {} - '@inquirer/checkbox@4.3.2(@types/node@26.6.5)': dependencies: '@inquirer/ansi': 1.0.2 @@ -4345,15 +3555,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/checkbox@5.2.5(@types/node@26.6.5)': - dependencies: - '@inquirer/ansi': 2.0.8 - '@inquirer/core': 12.0.3(@types/node@26.6.5) - '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.1.1(@types/node@26.6.5) - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/confirm@5.1.21(@types/node@26.6.5)': dependencies: '@inquirer/core': 10.3.2(@types/node@26.6.5) @@ -4361,13 +3562,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/confirm@6.3.2(@types/node@26.6.5)': - dependencies: - '@inquirer/core': 12.0.3(@types/node@26.6.5) - '@inquirer/type': 4.1.1(@types/node@26.6.5) - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/core@10.3.2(@types/node@26.6.5)': dependencies: '@inquirer/ansi': 1.0.2 @@ -4381,18 +3575,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/core@12.0.3(@types/node@26.6.5)': - dependencies: - '@inquirer/ansi': 2.0.8 - '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.1.1(@types/node@26.6.5) - cli-width: 4.1.0 - fast-wrap-ansi: 0.2.2 - mute-stream: 3.0.0 - signal-exit: 4.1.0 - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/editor@4.2.23(@types/node@26.6.5)': dependencies: '@inquirer/core': 10.3.2(@types/node@26.6.5) @@ -4401,14 +3583,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/editor@5.3.3(@types/node@26.6.5)': - dependencies: - '@inquirer/core': 12.0.3(@types/node@26.6.5) - '@inquirer/external-editor': 3.0.5(@types/node@26.6.5) - '@inquirer/type': 4.1.1(@types/node@26.6.5) - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/expand@4.0.23(@types/node@26.6.5)': dependencies: '@inquirer/core': 10.3.2(@types/node@26.6.5) @@ -4417,13 +3591,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/expand@5.1.5(@types/node@26.6.5)': - dependencies: - '@inquirer/core': 12.0.3(@types/node@26.6.5) - '@inquirer/type': 4.1.1(@types/node@26.6.5) - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/external-editor@1.0.3(@types/node@26.6.5)': dependencies: chardet: 2.2.0 @@ -4431,17 +3598,8 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/external-editor@3.0.5(@types/node@26.6.5)': - dependencies: - chardet: 2.2.0 - iconv-lite: 0.7.3 - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/figures@1.0.15': {} - '@inquirer/figures@2.0.9': {} - '@inquirer/input@4.3.1(@types/node@26.6.5)': dependencies: '@inquirer/core': 10.3.2(@types/node@26.6.5) @@ -4449,13 +3607,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/input@5.1.6(@types/node@26.6.5)': - dependencies: - '@inquirer/core': 12.0.3(@types/node@26.6.5) - '@inquirer/type': 4.1.1(@types/node@26.6.5) - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/number@3.0.23(@types/node@26.6.5)': dependencies: '@inquirer/core': 10.3.2(@types/node@26.6.5) @@ -4463,13 +3614,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/number@4.2.3(@types/node@26.6.5)': - dependencies: - '@inquirer/core': 12.0.3(@types/node@26.6.5) - '@inquirer/type': 4.1.1(@types/node@26.6.5) - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/password@4.0.23(@types/node@26.6.5)': dependencies: '@inquirer/ansi': 1.0.2 @@ -4478,14 +3622,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/password@5.2.2(@types/node@26.6.5)': - dependencies: - '@inquirer/ansi': 2.0.8 - '@inquirer/core': 12.0.3(@types/node@26.6.5) - '@inquirer/type': 4.1.1(@types/node@26.6.5) - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/prompts@7.10.1(@types/node@26.6.5)': dependencies: '@inquirer/checkbox': 4.3.2(@types/node@26.6.5) @@ -4501,21 +3637,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/prompts@8.7.2(@types/node@26.6.5)': - dependencies: - '@inquirer/checkbox': 5.2.5(@types/node@26.6.5) - '@inquirer/confirm': 6.3.2(@types/node@26.6.5) - '@inquirer/editor': 5.3.3(@types/node@26.6.5) - '@inquirer/expand': 5.1.5(@types/node@26.6.5) - '@inquirer/input': 5.1.6(@types/node@26.6.5) - '@inquirer/number': 4.2.3(@types/node@26.6.5) - '@inquirer/password': 5.2.2(@types/node@26.6.5) - '@inquirer/rawlist': 5.3.5(@types/node@26.6.5) - '@inquirer/search': 4.3.3(@types/node@26.6.5) - '@inquirer/select': 5.2.5(@types/node@26.6.5) - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/rawlist@4.1.11(@types/node@26.6.5)': dependencies: '@inquirer/core': 10.3.2(@types/node@26.6.5) @@ -4524,13 +3645,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/rawlist@5.3.5(@types/node@26.6.5)': - dependencies: - '@inquirer/core': 12.0.3(@types/node@26.6.5) - '@inquirer/type': 4.1.1(@types/node@26.6.5) - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/search@3.2.2(@types/node@26.6.5)': dependencies: '@inquirer/core': 10.3.2(@types/node@26.6.5) @@ -4540,14 +3654,6 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/search@4.3.3(@types/node@26.6.5)': - dependencies: - '@inquirer/core': 12.0.3(@types/node@26.6.5) - '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.1.1(@types/node@26.6.5) - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/select@4.4.2(@types/node@26.6.5)': dependencies: '@inquirer/ansi': 1.0.2 @@ -4558,23 +3664,10 @@ snapshots: optionalDependencies: '@types/node': 26.6.5 - '@inquirer/select@5.2.5(@types/node@26.6.5)': - dependencies: - '@inquirer/ansi': 2.0.8 - '@inquirer/core': 12.0.3(@types/node@26.6.5) - '@inquirer/figures': 2.0.9 - '@inquirer/type': 4.1.1(@types/node@26.6.5) - optionalDependencies: - '@types/node': 26.6.5 - '@inquirer/type@3.0.10(@types/node@26.6.5)': optionalDependencies: '@types/node': 26.6.5 - '@inquirer/type@4.1.1(@types/node@26.6.5)': - optionalDependencies: - '@types/node': 26.6.5 - '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -4611,11 +3704,6 @@ snapshots: '@types/yargs': 17.0.35 chalk: 4.1.2 - '@jridgewell/gen-mapping@0.4.0-beta.0': - dependencies: - '@jridgewell/sourcemap-codec': 1.6.0 - '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/sourcemap-codec@1.6.0': {} @@ -4718,72 +3806,6 @@ snapshots: '@sindresorhus/merge-streams@4.0.0': {} - '@stryker-mutator/api@10.0.0': - dependencies: - mutation-testing-metrics: 3.8.4 - mutation-testing-report-schema: 3.8.4 - tslib: 2.8.1 - typed-inject: 5.0.0 - - '@stryker-mutator/core@10.0.0(@types/node@26.6.5)': - dependencies: - '@inquirer/prompts': 8.7.2(@types/node@26.6.5) - '@stryker-mutator/api': 10.0.0 - '@stryker-mutator/instrumenter': 10.0.0 - '@stryker-mutator/util': 10.0.0 - ajv: 8.20.0 - chalk: 5.6.2 - commander: 14.0.3 - diff-match-patch: 1.0.5 - emoji-regex: 10.6.0 - execa: 9.6.1 - json-rpc-2.0: 1.8.1 - lodash.groupby: 4.6.0 - minimatch: 10.2.6 - mutation-server-protocol: 0.4.1 - mutation-testing-elements: 3.8.4 - mutation-testing-metrics: 3.8.4 - mutation-testing-report-schema: 3.8.4 - npm-run-path: 6.0.0 - progress: 2.0.3 - rxjs: 7.8.2 - semver: 7.8.5 - source-map: 0.7.6 - tree-kill: 1.2.2 - tslib: 2.8.1 - typed-inject: 5.0.0 - typed-rest-client: 2.3.1 - transitivePeerDependencies: - - '@types/node' - - '@stryker-mutator/instrumenter@10.0.0': - dependencies: - '@babel/core': 8.0.6 - '@babel/generator': 8.0.6 - '@babel/parser': 8.0.6 - '@babel/plugin-proposal-decorators': 8.0.2(@babel/core@8.0.6) - '@babel/plugin-transform-explicit-resource-management': 8.0.5(@babel/core@8.0.6) - '@babel/preset-react': 8.0.1(@babel/core@8.0.6) - '@babel/preset-typescript': 8.0.1(@babel/core@8.0.6) - '@babel/traverse': 8.0.6 - '@stryker-mutator/api': 10.0.0 - '@stryker-mutator/util': 10.0.0 - angular-html-parser: 10.11.0 - semver: 7.8.5 - tslib: 2.8.1 - weapon-regex: 2.0.5 - - '@stryker-mutator/util@10.0.0': {} - - '@stryker-mutator/vitest-runner@10.0.0(patch_hash=c5d635178da5a48e07051030a6d2eb3f33f4b31a71f4232c05f099e8e90f3dc2)(@stryker-mutator/core@10.0.0(@types/node@26.6.5))(vitest@5.0.5)': - dependencies: - '@stryker-mutator/api': 10.0.0 - '@stryker-mutator/core': 10.0.0(@types/node@26.6.5) - '@stryker-mutator/util': 10.0.0 - semver: 7.8.5 - tslib: 2.8.1 - vitest: 5.0.5(@types/node@26.6.5)(@vitest/coverage-v8@5.0.5)(vite@8.3.4(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)) - '@stylistic/eslint-plugin@5.10.0(eslint@10.13.0(jiti@2.7.0)(supports-color@8.1.1))': dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.13.0(jiti@2.7.0)(supports-color@8.1.1)) @@ -4864,8 +3886,6 @@ snapshots: '@types/filewriter@0.0.33': {} - '@types/gensync@1.0.5': {} - '@types/har-format@1.2.16': {} '@types/istanbul-lib-coverage@2.0.6': {} @@ -4878,8 +3898,6 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 - '@types/jsesc@2.5.1': {} - '@types/json-schema@7.0.15': {} '@types/minimatch@3.0.5': {} @@ -5352,8 +4370,6 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - angular-html-parser@10.11.0: {} - ansi-align@3.0.1: dependencies: string-width: 4.2.3 @@ -5452,8 +4468,6 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.11.26: {} - bcp-47-match@2.0.3: {} boolbase@1.0.0: {} @@ -5484,14 +4498,6 @@ snapshots: browser-stdout@1.3.1: {} - browserslist@4.29.3: - dependencies: - baseline-browser-mapping: 2.11.26 - caniuse-lite: 1.0.30001814 - electron-to-chromium: 1.5.443 - node-releases: 2.0.57 - update-browserslist-db: 1.3.3(browserslist@4.29.3) - buffer-crc32@1.0.0: {} buffer-equal-constant-time@1.0.1: {} @@ -5515,22 +4521,10 @@ snapshots: keyv: 5.6.0 qified: 0.10.1 - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - callsites@3.1.0: {} camelcase@8.0.0: {} - caniuse-lite@1.0.30001814: {} - chai@6.3.0: {} chalk@4.1.2: @@ -5752,15 +4746,8 @@ snapshots: define-lazy-prop@3.0.0: {} - des.js@1.1.0: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - detect-libc@2.1.2: {} - diff-match-patch@1.0.5: {} - diff@8.0.4: {} diff@9.0.0: {} @@ -5789,12 +4776,6 @@ snapshots: dotenv@17.4.2: {} - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - eastasianwidth@0.2.0: {} easy-table@1.2.0: @@ -5836,8 +4817,6 @@ snapshots: emoji-regex@9.2.2: {} - empathic@2.1.0: {} - encoding-sniffer@0.2.1: dependencies: iconv-lite: 0.6.3 @@ -5853,16 +4832,8 @@ snapshots: dependencies: is-arrayish: 0.2.1 - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - es-module-lexer@2.3.2: {} - es-object-atoms@1.1.2: - dependencies: - es-errors: 1.3.0 - es6-error@4.1.1: {} esbuild@0.28.2: @@ -6102,18 +5073,8 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-string-truncated-width@3.0.3: {} - - fast-string-width@3.0.2: - dependencies: - fast-string-truncated-width: 3.0.3 - fast-uri@3.1.8: {} - fast-wrap-ansi@0.2.2: - dependencies: - fast-string-width: 3.0.2 - fdir@6.5.0(picomatch@4.0.7): optionalDependencies: picomatch: 4.0.7 @@ -6169,8 +5130,6 @@ snapshots: flatted@3.4.4: {} - flru@1.0.2: {} - foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 @@ -6185,8 +5144,6 @@ snapshots: fsevents@2.3.3: optional: true - function-bind@1.1.2: {} - fuse.js@7.5.0: {} fx-runner@1.7.0: @@ -6215,32 +5172,12 @@ snapshots: modern-tar: 0.8.5 undici: 8.11.2 - gensync@1.0.0-beta.2: {} - get-caller-file@2.0.5: {} get-east-asian-width@1.6.0: {} - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.2 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.4 - math-intrinsics: 1.1.0 - get-port@7.2.0: {} - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.2 - get-stream@9.0.1: dependencies: '@sec-ant/readable-stream': 0.4.1 @@ -6275,8 +5212,6 @@ snapshots: globals@17.13.0: {} - gopd@1.2.0: {} - graceful-fs@4.2.10: {} graceful-fs@4.2.11: {} @@ -6285,16 +5220,10 @@ snapshots: has-flag@4.0.0: {} - has-symbols@1.1.0: {} - hashery@1.5.1: dependencies: hookified: 1.15.1 - hasown@2.0.4: - dependencies: - function-bind: 1.1.2 - hls.js@1.7.3(patch_hash=7bf3c8187174dcdd9951f64f89092432f2c76698ca18dc4b55b45b62c78c9b5a): {} hookified@1.15.1: {} @@ -6505,8 +5434,6 @@ snapshots: jose@5.9.6: {} - js-md4@0.3.2: {} - js-tokens@10.0.0: {} js-tokens@4.0.0: {} @@ -6519,8 +5446,6 @@ snapshots: dependencies: argparse: 3.0.3 - jsesc@3.1.0: {} - json-buffer@3.0.1: {} json-merge-patch@1.0.2: @@ -6529,16 +5454,12 @@ snapshots: json-parse-even-better-errors@3.0.2: {} - json-rpc-2.0@1.8.1: {} - json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} json-stable-stringify-without-jsonify@1.0.1: {} - json5@2.2.3: {} - jsonfile@6.2.1: dependencies: universalify: 2.0.1 @@ -6687,8 +5608,6 @@ snapshots: lodash.flattendeep@4.4.0: {} - lodash.groupby@4.6.0: {} - lodash.includes@4.3.0: {} lodash.isboolean@3.0.3: {} @@ -6735,8 +5654,6 @@ snapshots: marky@1.3.0: {} - math-intrinsics@1.1.0: {} - mdn-data@2.27.1: {} mediabunny@1.61.6: @@ -6744,8 +5661,6 @@ snapshots: '@types/dom-mediacapture-transform': 0.1.12 '@types/dom-webcodecs': 0.1.13 - minimalistic-assert@1.0.1: {} - minimatch@10.2.6: dependencies: brace-expansion: 5.0.12 @@ -6800,28 +5715,12 @@ snapshots: array-union: 3.0.1 minimatch: 3.1.5 - mutation-server-protocol@0.4.1: - dependencies: - zod: 4.6.5 - - mutation-testing-elements@3.8.4: {} - - mutation-testing-metrics@3.8.4: - dependencies: - mutation-testing-report-schema: 3.8.4 - - mutation-testing-report-schema@3.8.4: {} - mute-stream@2.0.0: {} - mute-stream@3.0.0: {} - nanoid@3.3.20: {} natural-compare@1.4.0: {} - node-releases@2.0.57: {} - normalize-package-data@6.0.2: dependencies: hosted-git-info: 7.0.2 @@ -6847,8 +5746,6 @@ snapshots: object-inspect@1.13.4: {} - obug@2.2.1: {} - obug@3.0.0: {} on-exit-leak-free@2.1.2: {} @@ -7022,8 +5919,6 @@ snapshots: process@0.11.10: {} - progress@2.0.3: {} - promise-toolbox@0.21.0: dependencies: make-error: 1.3.6 @@ -7042,11 +5937,6 @@ snapshots: dependencies: hookified: 2.2.0 - qs@6.16.0: - dependencies: - es-define-property: 1.0.1 - side-channel: 1.1.1 - query-selector-shadow-dom@1.0.1: {} quick-format-unescaped@4.0.4: {} @@ -7188,34 +6078,6 @@ snapshots: shell-quote@1.12.0: {} - side-channel-list@1.0.1: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.1: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.1 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - signal-exit@4.1.0: {} slash@3.0.0: {} @@ -7235,8 +6097,6 @@ snapshots: source-map@0.6.1: {} - source-map@0.7.6: {} - spacetrim@0.11.59: {} spdx-correct@3.2.0: @@ -7387,8 +6247,6 @@ snapshots: tmp@0.2.7: {} - tree-kill@1.2.2: {} - tslib@2.8.1: {} tsx@4.23.15: @@ -7397,8 +6255,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - tunnel@0.0.6: {} - type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -7409,16 +6265,6 @@ snapshots: type-fest@4.41.0: {} - typed-inject@5.0.0: {} - - typed-rest-client@2.3.1: - dependencies: - des.js: 1.1.0 - js-md4: 0.3.2 - qs: 6.16.0 - tunnel: 0.0.6 - underscore: 1.13.8 - typescript@7.0.2: optionalDependencies: '@typescript/typescript-aix-ppc64': 7.0.2 @@ -7442,8 +6288,6 @@ snapshots: '@typescript/typescript-win32-arm64': 7.0.2 '@typescript/typescript-win32-x64': 7.0.2 - underscore@1.13.8: {} - undici-types@6.21.0: {} undici-types@8.9.0: {} @@ -7458,12 +6302,6 @@ snapshots: upath@3.0.8: {} - update-browserslist-db@1.3.3(browserslist@4.29.3): - dependencies: - browserslist: 4.29.3 - escalade: 3.2.0 - picocolors: 1.1.1 - update-notifier@7.3.1: dependencies: boxen: 8.0.1 @@ -7492,8 +6330,6 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - verkit@0.3.2: {} - vite@8.3.4(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15): dependencies: lightningcss: 1.33.0 @@ -7546,8 +6382,6 @@ snapshots: dependencies: defaults: 1.0.4 - weapon-regex@2.0.5: {} - web-ext@10.8.0(jiti@2.7.0)(supports-color@8.1.1): dependencies: '@babel/runtime': 8.0.7 @@ -7755,5 +6589,3 @@ snapshots: compress-commons: 7.0.1 normalize-path: 3.0.0 readable-stream: 4.7.0 - - zod@4.6.5: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b771c687c..1a7c767de 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -20,10 +20,6 @@ overrides: # so each keeps its own. undici@6: ^6.28.1 undici@7: ^7.29.1 - # Dependabot #56-#58: @stryker-mutator/core 10.0.0 (its newest) wants typed-rest-client - # ~2.3.0, which pins qs to exactly 6.15.1; typed-rest-client 3 moved to ^6.16.0. Stryker - # uses it only for `stryker init` and its dashboard reporter, neither of which runs here. - qs: ^6.16.0 # Dependabot #59 (high): basic-ftp <= 6.2.0 parses a directory listing in quadratic time. # @puppeteer/browsers -> proxy-agent -> pac-proxy-agent -> get-uri, whose newest release # (8.0.1) still asks for ^5.3.1, brings 5.3.1, so the fix (6.2.1) needs this. 6.0.0's one @@ -55,7 +51,6 @@ allowBuilds: dtrace-provider: false spawn-sync: false patchedDependencies: - '@stryker-mutator/vitest-runner@10.0.0': patches/@stryker-mutator__vitest-runner@10.0.0.patch Coloris@0.25.0: patches/Coloris@0.25.0.patch dashjs@5.2.1: patches/dashjs@5.2.1.patch gif.js@0.2.0: patches/gif.js@0.2.0.patch diff --git a/stryker.config.mjs b/stryker.config.mjs deleted file mode 100644 index e6344bbcb..000000000 --- a/stryker.config.mjs +++ /dev/null @@ -1,227 +0,0 @@ -// Mutation testing (T4): `pnpm run test:mutation`, and weekly on CI (mutation-tests.yml). -// -// Stryker changes one thing at a time in the modules below - a comparison, a bound, a -// call left out - and runs the unit tests against each change. A change the tests still -// pass is a place where a fix could ship without a test that fails without it: the rule -// every fix here follows, checked by hand until now. The weekly run reports; it does not -// gate (no break threshold). -// -// Only pure-logic modules with unit tests: the DOM and the player are the e2e suites'. -// In four areas (#253): `core`, `network` (the downloader, the loaders and what they use), -// `tools` (the tools and e2e harness modules with unit tests) and `host` (the mpv host, on -// the command runner), each split into shards (SHARDS, below) that mutation-tests.yml runs -// side by side, each in a job of its own. STRYKER_SHARD picks one; without it, all of them run (`pnpm run test:mutation`, -// locally). -// -// How long an area took with the command runner, measured on CI (#349, run 37333779402, -// 2026-10-05): network 7 mutants a minute, core 14, tools 10 - with ~3,300, ~5,100 and -// ~3,200 mutants, 7.7, 6 and 5.3 hours. The first estimate (1.2 s a mutant, 2026-10-04) was a local run's: on CI a -// mutant the tests do not catch runs the whole suite (~18 s), and a third to a half of -// them survive. One job an area ran out of its 240 minutes at 51-74%, and no report came. -// So each area was cut into PARTS shards of about the same size, each a few hours; with the -// vitest runner (below) a shard should take minutes, measured on its first CI run. -// -// The weekly job runs on Linux: the mpv host's Windows-only tests (mpvHostInstall, the -// PowerShell cases of mpvHostSecurity) are skipped there, so its PowerShell and WMI -// mutants can only survive, and count against its score. -// -// Stryker's vitest runner, with per-test coverage: a mutant runs only the tests that reached -// its code, in a Vitest that stays up between mutants - 143 mutants in 31 s on a PC -// (2026-10-06), where the command runner ran the whole unit suite for each, ~18 s a mutant -// on CI, the hours above. Its 10.0.0 release (August 2026) predates Vitest 5, which joins a -// test's suite chain with ' > ': its test filter matched nothing and every mutant -// "survived" (stryker-js #6210). FastStream carries the fix, stryker-js PR #6214, as a pnpm -// patch (patches/@stryker-mutator__vitest-runner@10.0.0.patch); the Patched libraries -// workflow drops it once a release has it, and moves @stryker-mutator/core with the runner -// (LOCKSTEP in tools/check-patched-updates.mjs). -// -// A mutant is switched on inside the test worker, so a test that runs a module as a process -// of its own does not see it there. For the mpv host that left its message loop untested, -// so the host keeps the command runner (COMMAND_AREAS); the tools' tests that start their -// tool as a process only reach its entry line, where the vitest runner sees a crashed run. -import fs from 'node:fs'; - -export const AREAS = { - core: [ - 'chrome/background/CustomSourcePatterns.mjs', - 'chrome/background/DownloadFilename.mjs', - 'chrome/background/KeyShortcut.mjs', - 'chrome/background/ManifestTypes.mjs', - 'chrome/background/MpvBackend.mjs', - 'chrome/background/MultiRegexMatcher.mjs', - 'chrome/background/StreamLengths.mjs', - 'chrome/background/TabTracker.mjs', - 'chrome/background/UrlMatchList.mjs', - 'chrome/player/modules/LargeBuffer.mjs', - 'chrome/player/modules/hls2mp4/ptsNormalize.mjs', - 'chrome/player/modules/remux/TimestampRebaser.mjs', - 'chrome/player/network/OpQueue.mjs', - 'chrome/player/network/SpeedTracker.mjs', - 'chrome/player/options/KeybindUtils.mjs', - 'chrome/player/players/hls/HLSDecrypter.mjs', - 'chrome/player/players/mp4/SourceBufferWrapper.mjs', - 'chrome/player/players/mp4/StallWatchdog.mjs', - 'chrome/player/ui/FrameStepper.mjs', - 'chrome/player/utils/StreamLength.mjs', - 'chrome/player/utils/StreamPick.mjs', - 'chrome/player/utils/SubtitleSyncUtils.mjs', - 'chrome/player/utils/SubtitleUtils.mjs', - 'chrome/player/utils/URLUtils.mjs', - ], - network: [ - 'chrome/background/BackgroundUtils.mjs', - 'chrome/background/NetRequestRuleManager.mjs', - 'chrome/player/modules/SecureMemory.mjs', - 'chrome/player/network/DownloadEntry.mjs', - 'chrome/player/network/DownloadManager.mjs', - 'chrome/player/network/OPFSManager.mjs', - 'chrome/player/network/StandardDownloader.mjs', - 'chrome/player/network/FetchLoader.mjs', - 'chrome/player/players/LevelManager.mjs', - 'chrome/player/players/SyncedAudioPlayer.mjs', - 'chrome/player/players/dash/DashLoader.mjs', - 'chrome/player/players/hls/HLSFragmentRequester.mjs', - 'chrome/player/players/hls/HLSLoader.mjs', - 'chrome/player/utils/StringUtils.mjs', - ], - tools: [ - 'tests/e2e/bidi.mjs', - 'tests/e2e/mozLog.mjs', - 'tests/e2e/mp4Fixture.mjs', - 'tests/e2e/reportRetried.mjs', - 'tests/e2e/retriedSpecs.mjs', - 'tests/e2e/serveFile.mjs', - 'tests/e2e/setupGuard.mjs', - 'tests/e2e/shardSpecs.mjs', - 'tests/e2e/testTimeout.mjs', - 'tools/check-patched-updates.mjs', - 'tools/check-toolchain.mjs', - 'tools/check-update-path.mjs', - 'tools/e2e-spec-weights.mjs', - 'tools/fetch-amo-signed.mjs', - 'tools/mutation-report.mjs', - 'tools/newest-release.mjs', - 'tools/recut-patch.mjs', - 'tools/sign-amo.mjs', - 'tools/verify-linux.mjs', - ], - // The mpv host, with the command runner (COMMAND_AREAS, below). - host: ['native-host/faststream-mpv-host.mjs'], -}; - -// The areas Stryker runs with the command runner, every mutant against the whole unit suite -// in a process of its own, which hands the active mutant to the processes a test starts -// (__STRYKER_ACTIVE_MUTANT__). The vitest runner switches a mutant on inside the test worker -// only, and the mpv host's message loop - main() and sendMessage(), which run only in the -// host process mpvHostVersion.test.mjs starts and talks to - had no test reaching it there: -// 24 of its mutants the command runner caught were "no coverage" (CI runs 37384050152 and -// 37393654214, compared mutant by mutant, 2026-10-06). Every other module came out the same -// (11,313 of 11,370 alike; the rest a crashed run for a caught one, or two swapped on a line). -export const COMMAND_AREAS = ['host']; - -// How many shards each area is cut into. With the vitest runner one each: on CI the seven -// shards of 2026-10-06 took 2 to 10 minutes (core 7 and 10, network 2 to 3, tools 2 to 3). -// The host, on the command runner, about an hour and a half at core's 14 mutants a minute, -// inside its job's 350 minutes (mutation-tests.yml). -export const PARTS = {core: 1, network: 1, tools: 1, host: 1}; - -/** - * An area's modules in `parts` groups of about the same size, the size of a file standing - * for how many mutants it gives: the largest first, each to the group with the least so far. - * The same files give the same groups, so a shard's name always means the same modules. - * @param {string[]} modules - The area's modules. - * @param {number} parts - How many groups. - * @return {string[][]} The groups, each in the area's own order. - */ -export function splitArea(modules, parts) { - const size = (file) => { - try { - return fs.statSync(new URL(file, import.meta.url)).size; - } catch { - return 0; - } - }; - const groups = Array.from({length: parts}, () => ({files: new Set(), size: 0})); - const bySize = modules.map((file) => ({file, size: size(file)})) - .sort((a, b) => b.size - a.size || a.file.localeCompare(b.file)); - for (const {file, size: bytes} of bySize) { - const lightest = groups.reduce((min, group) => group.size < min.size ? group : min); - lightest.files.add(file); - lightest.size += bytes; - } - return groups.map((group) => modules.filter((file) => group.files.has(file))); -} - -// core-1, network-1, tools-1, host-1: the shards mutation-tests.yml runs, one job each. -export const SHARDS = Object.fromEntries(Object.entries(AREAS).flatMap(([area, modules]) => - splitArea(modules, PARTS[area]).map((group, i) => [`${area}-${i + 1}`, group]))); - -/** - * The modules a run mutates. - * @param {string|undefined} shard - STRYKER_SHARD: a key of SHARDS, or empty for all. - * @return {string[]} - */ -export function modulesOf(shard) { - if (!shard) { - return Object.values(SHARDS).flat(); - } - if (!Object.hasOwn(SHARDS, shard)) { - throw new Error(`STRYKER_SHARD is ${shard}: it is one of ${Object.keys(SHARDS).join(', ')}`); - } - return SHARDS[shard]; -} - -/** - * The test runner settings for a shard: the command runner for one of COMMAND_AREAS, the - * vitest runner otherwise - and for a run of everything at once (`pnpm run test:mutation` - * with no STRYKER_SHARD), where the host's message loop then shows as no coverage. - * @param {string|undefined} shard - STRYKER_SHARD. - * @return {Object} - */ -export function runnerOf(shard) { - if (shard && COMMAND_AREAS.some((area) => shard.startsWith(`${area}-`))) { - return { - testRunner: 'command', - commandRunner: {command: 'node node_modules/vitest/vitest.mjs run --bail=1 --reporter=dot'}, - coverageAnalysis: 'off', - }; - } - return { - testRunner: 'vitest', - // pnpm's layout: Stryker looks for @stryker-mutator/* plugins beside its own core only. - plugins: ['@stryker-mutator/vitest-runner'], - vitest: {configFile: 'vitest.config.mjs'}, - coverageAnalysis: 'perTest', - }; -} - -export default { - ...runnerOf(process.env.STRYKER_SHARD), - // What the sandbox leaves out: builds, profiles, logs and fixtures the unit tests never - // read, and tsconfig.json, which Stryker would rewrite through TypeScript's JS API - - // TypeScript 7 has none (`ts.parseConfigFileTextToJson is not a function`). - ignorePatterns: [ - 'tsconfig.json', - '/.dev-profile*', - '/build_firefox_*', - '/built', - '/logs', - '/logs-moz', - '/.e2e-downloads', - '/reports', - '/coverage', - '/tests/e2e/fixtures', - '/fsaunpack', - '/docs', - ], - // Nothing here is TypeScript, and its HTML files do not parse as Stryker expects. - disableTypeChecks: false, - mutate: modulesOf(process.env.STRYKER_SHARD), - reporters: ['clear-text', 'progress', 'html', 'json'], - htmlReporter: {fileName: 'reports/mutation/index.html'}, - jsonReporter: {fileName: 'reports/mutation/mutation.json'}, - thresholds: {high: 80, low: 60, break: null}, - concurrency: 4, - timeoutMS: 60000, - incremental: false, -}; diff --git a/tests/unit/checkPatchedUpdates.test.mjs b/tests/unit/checkPatchedUpdates.test.mjs index 776cf2c99..c7b0ae008 100644 --- a/tests/unit/checkPatchedUpdates.test.mjs +++ b/tests/unit/checkPatchedUpdates.test.mjs @@ -1,6 +1,6 @@ import fs from 'node:fs'; import {describe, expect, it} from 'vitest'; -import {LOCKSTEP, compareVersions, githubRepo, patchedDependencies} from '../../tools/check-patched-updates.mjs'; +import {compareVersions, githubRepo, patchedDependencies} from '../../tools/check-patched-updates.mjs'; // The patched libraries are left out of Dependabot, and this script is what still notices // their updates. Reading the list wrongly, or comparing versions as text, would hide an @@ -11,7 +11,7 @@ const yaml = fs.readFileSync(new URL('../../pnpm-workspace.yaml', import.meta.ur describe('patchedDependencies', () => { it('reads every patched library with the version its patch is cut against', () => { const libraries = patchedDependencies(yaml); - expect(libraries.length).toBeGreaterThanOrEqual(6); + expect(libraries.length).toBeGreaterThanOrEqual(5); expect(libraries).toContainEqual({name: 'hls.js', version: '1.7.3'}); expect(libraries).toContainEqual({name: 'Coloris', version: '0.25.0'}); for (const {name, version} of libraries) { @@ -43,22 +43,10 @@ describe('patchedDependencies', () => { } }); - it('is the list Dependabot is told to ignore, with the packages that move with them', () => { + it('is the list Dependabot is told to ignore', () => { const dependabot = fs.readFileSync(new URL('../../.github/dependabot.yml', import.meta.url), 'utf8'); const ignored = [...dependabot.matchAll(/dependency-name: '([^']+)'/g)].map((match) => match[1]).sort(); - const patched = patchedDependencies(yaml).map(({name}) => name); - expect(ignored).toEqual([...patched, ...patched.flatMap((name) => LOCKSTEP[name] || [])].sort()); - }); - - it('pins what moves with a patched library to the library\'s own version', () => { - // @stryker-mutator/vitest-runner requires @stryker-mutator/core at its version exactly: - // apart, Stryker runs with a runner its core was not made for. - const pkg = JSON.parse(fs.readFileSync(new URL('../../package.json', import.meta.url), 'utf8')); - const declared = {...pkg.dependencies, ...pkg.devDependencies}; - for (const {name, version} of patchedDependencies(yaml)) { - for (const companion of LOCKSTEP[name] || []) expect(declared[companion], companion).toBe(version); - } - expect(LOCKSTEP['@stryker-mutator/vitest-runner']).toEqual(['@stryker-mutator/core']); + expect(ignored).toEqual(patchedDependencies(yaml).map(({name}) => name).sort()); }); it('leaves the other libraries the build copies to Dependabot\'s shipped group', () => { diff --git a/tests/unit/decodeSubtitleBytes.test.mjs b/tests/unit/decodeSubtitleBytes.test.mjs index 7344db250..bc3644206 100644 --- a/tests/unit/decodeSubtitleBytes.test.mjs +++ b/tests/unit/decodeSubtitleBytes.test.mjs @@ -4,7 +4,6 @@ import {afterEach, describe, expect, it, vi} from 'vitest'; import {RequestUtils} from '../../chrome/player/utils/RequestUtils.mjs'; import {SubtitleUtils} from '../../chrome/player/utils/SubtitleUtils.mjs'; import {installFakeDom} from './fakeCueDom.mjs'; -import {isMutationSandboxCopy} from './helpers/stryker.mjs'; // Subtitle files reach the player as bytes, from six places. Read the browser's way (UTF-8 // unless the file or the server says otherwise), an older SubRip file saved as @@ -149,9 +148,7 @@ describe('decodeSubtitleBytes at the places subtitle files come in', () => { expect(read('player/ui/subtitles/SubtitlesManager.mjs').match(/decodeSubtitleBytes\(/g)).toHaveLength(2); }); - // Not where Stryker rewrote SubtitleUtils: its copy is no longer the text content.js - // carries (helpers/stryker.mjs). - it.skipIf(isMutationSandboxCopy(read('player/utils/SubtitleUtils.mjs')))('content.js carries the same decodeSubtitleBytes', () => { + it('content.js carries the same decodeSubtitleBytes', () => { // content.js is a classic script and cannot import SubtitleUtils, so it has a copy. const body = (source, signature) => { const start = source.indexOf(signature); diff --git a/tests/unit/fetchAmoSigned.test.mjs b/tests/unit/fetchAmoSigned.test.mjs index 9a5aec23c..551941f7d 100644 --- a/tests/unit/fetchAmoSigned.test.mjs +++ b/tests/unit/fetchAmoSigned.test.mjs @@ -1,7 +1,6 @@ import fs from 'node:fs'; import {describe, expect, it} from 'vitest'; import {EXIT, isNetworkError, parseArgs, signingState, waitForSigned} from '../../tools/fetch-amo-signed.mjs'; -import {isMutationSandboxCopy} from './helpers/stryker.mjs'; // The AMO signing failsafe acts on what signingState answers: collect the xpi, wait, // upload again, or tell the owner. A wrong answer either never collects a signed build @@ -10,8 +9,7 @@ import {isMutationSandboxCopy} from './helpers/stryker.mjs'; describe('authentication', () => { const source = fs.readFileSync(new URL('../../tools/fetch-amo-signed.mjs', import.meta.url), 'utf8'); - // Stryker's rewrite of the module says nothing about its imports (helpers/stryker.mjs). - it.skipIf(isMutationSandboxCopy(source))('uses the AMO authentication of web-ext, which every release signs with', () => { + it('uses the AMO authentication of web-ext, which every release signs with', () => { // A token built by hand could drift from what AMO accepts; web-ext's is proven by // every release.yml run. expect(source).toMatch(/import \{JwtApiAuth\} from 'web-ext\/util\/submit-addon';/); diff --git a/tests/unit/helpers/stryker.mjs b/tests/unit/helpers/stryker.mjs deleted file mode 100644 index 335947edd..000000000 --- a/tests/unit/helpers/stryker.mjs +++ /dev/null @@ -1,15 +0,0 @@ -// Stryker's mutation runs (stryker.config.mjs) run the unit suite in a copy of the -// repository in which every module they mutate is rewritten: each expression wrapped in -// stryMutAct_/stryCov_ calls. A test that reads such a module as text - to check what it -// says, not what it does - cannot pass there, and it failed the run's first, unmutated pass -// (mutation-tests.yml, #349). It skips in that copy instead; in a normal run the file is the -// repository's own, and the test runs. - -/** - * Whether a module's text is Stryker's rewrite of it. - * @param {string} source - The file's text. - * @return {boolean} - */ -export function isMutationSandboxCopy(source) { - return /\bstry(?:MutAct|Cov)_[0-9a-f]+\(/.test(source); -} diff --git a/tests/unit/mpvHostInstall.test.mjs b/tests/unit/mpvHostInstall.test.mjs index d76bdb439..b41742324 100644 --- a/tests/unit/mpvHostInstall.test.mjs +++ b/tests/unit/mpvHostInstall.test.mjs @@ -15,9 +15,8 @@ import {Capabilities, HostVersion} from '../../native-host/faststream-mpv-host.m const root = path.resolve(import.meta.dirname, '../..'); // "José 中文", from code points: the file tools used to write this suite mangle escapes. const FOLDER = 'Jos' + String.fromCodePoint(0xE9) + ' ' + String.fromCodePoint(0x4E2D, 0x6587); -// A host that never answers (a mutation test's endless read loop, a real hang) used to outlive -// the run: Stryker gives up on a mutant about a minute in, before this test's own timeout, and -// nothing stopped the host, which spun a core for good. A ping answers well within this. +// A host that never answers (an endless read loop, a real hang) would outlive the run: nothing +// would stop it, and it would spin a core for good. A ping answers well within this. const REPLY_TIMEOUT_MS = 15000; let dir; diff --git a/tests/unit/mpvHostVersion.test.mjs b/tests/unit/mpvHostVersion.test.mjs index 4279a99ab..0ed415033 100644 --- a/tests/unit/mpvHostVersion.test.mjs +++ b/tests/unit/mpvHostVersion.test.mjs @@ -37,10 +37,6 @@ const RECORDED = { installer: 'db3b8027b508556b8af66eb4b8188460c2a5a6e1feb32d32b490f2e234b29b3a', }; -// Stryker runs this suite on a copy of the host with every mutant written into it -// (.stryker-tmp/sandbox-*), which is never the recorded file. -const inMutationSandbox = root.split(path.sep).includes('.stryker-tmp'); - /** * A file's SHA-256, its line ends read as LF (a Windows checkout may have CRLF). * @param {string} file - The file. @@ -52,7 +48,7 @@ function sha256Of(file) { } describe('the mpv host\'s version', () => { - it.skipIf(inMutationSandbox)('is raised with every change to the host or its installer', () => { + it('is raised with every change to the host or its installer', () => { const next = HostVersion === RECORDED.version ? HostVersion + 1 : HostVersion; expect({version: HostVersion, host: sha256Of(hostFile), installer: sha256Of(installerFile)}, 'native-host/faststream-mpv-host.mjs or install.ps1 changed. A PC keeps running its ' + diff --git a/tests/unit/mutationReport.test.mjs b/tests/unit/mutationReport.test.mjs deleted file mode 100644 index 0d51a2582..000000000 --- a/tests/unit/mutationReport.test.mjs +++ /dev/null @@ -1,71 +0,0 @@ -import {describe, expect, it} from 'vitest'; -import {issueBody, merge, missed, perFile, summary} from '../../tools/mutation-report.mjs'; - -// mutation-tests.yml's summary table and weekly issue, from Stryker's report. - -const mutant = (status, line, mutatorName = 'EqualityOperator', replacement = 'a <= b') => - ({status, mutatorName, replacement, location: {start: {line, column: 1}, end: {line, column: 9}}}); - -const report = { - files: { - 'chrome/player/utils/StreamPick.mjs': {mutants: [ - mutant('Killed', 3), mutant('Killed', 4), mutant('Timeout', 5), mutant('Survived', 9, 'ConditionalExpression', 'true'), - ]}, - 'chrome/background/DownloadFilename.mjs': {mutants: [ - mutant('NoCoverage', 20, 'StringLiteral', '""'), mutant('Killed', 2), mutant('Ignored', 1), mutant('CompileError', 7), - ]}, - }, -}; - -describe('mutation-report', () => { - it('counts each file\'s caught (killed, timed out) and not caught (survived, no coverage) mutants', () => { - expect(perFile(report)).toEqual([ - {file: 'chrome/background/DownloadFilename.mjs', total: 4, caught: 1, missed: 1, score: 50}, - {file: 'chrome/player/utils/StreamPick.mjs', total: 4, caught: 3, missed: 1, score: 75}, - ]); - }); - - it('writes a row per file and the total', () => { - const text = summary(report); - expect(text).toContain('| chrome/player/utils/StreamPick.mjs | 4 | 3 | 1 | 75% |'); - expect(text).toContain('| **All** | 8 | 4 | 2 | 66.7% |'); - }); - - it('lists what was not caught, by file and line', () => { - expect(missed(report).map((m) => `${m.file}:${m.line} ${m.status}`)).toEqual([ - 'chrome/background/DownloadFilename.mjs:20 NoCoverage', - 'chrome/player/utils/StreamPick.mjs:9 Survived', - ]); - }); - - it('writes the issue: who to tell, the run, and each mutant with what the line became', () => { - const body = issueBody(report, 'Nawid3333', 'https://github.com/x/y/actions/runs/1'); - expect(body).toMatch(/^@Nawid3333 The unit tests did not catch 2 of this week's mutants/); - expect(body).toContain('Run: https://github.com/x/y/actions/runs/1'); - expect(body).toContain('- line 20: no test reaches it - StringLiteral: `""`'); - expect(body).toContain('- line 9: survived - ConditionalExpression: `true`'); - }); - - it('keeps a replacement from breaking the list, and shows at most 100 mutants', () => { - const many = {files: {'a.mjs': {mutants: Array.from({length: 150}, (_, i) => mutant('Survived', i + 1, 'X', 'a | `b`\nc'))}}}; - const body = issueBody(many, 'o', 'r'); - expect(body).toContain('### Not caught (the first 100 of 150)'); - expect(body).toContain('- line 1: survived - X: `a \\| \'b\' c`'); - expect(body.match(/^- line /gm)).toHaveLength(100); - }); - - it('puts the shards\' reports together, every file of each (#253)', () => { - const network = {schemaVersion: '2', files: {'chrome/player/network/FetchLoader.mjs': {mutants: [mutant('Survived', 4)]}}}; - const merged = merge([{schemaVersion: '2', ...report}, network]); - expect(merged.schemaVersion).toBe('2'); - expect(Object.keys(merged.files).sort()).toEqual([ - 'chrome/background/DownloadFilename.mjs', 'chrome/player/network/FetchLoader.mjs', 'chrome/player/utils/StreamPick.mjs', - ]); - expect(missed(merged)).toHaveLength(3); - expect(merge([])).toEqual({files: {}}); - }); - - it('refuses a module two shards both report', () => { - expect(() => merge([report, report])).toThrow(/is in two reports/); - }); -}); diff --git a/tests/unit/recutPatch.test.mjs b/tests/unit/recutPatch.test.mjs index 5fbf8b89b..bd0208c28 100644 --- a/tests/unit/recutPatch.test.mjs +++ b/tests/unit/recutPatch.test.mjs @@ -160,32 +160,18 @@ describe('checkJavaScript', () => { }); }); -// The update pull request for a patched library also moves what must stay at its version -// (LOCKSTEP: Stryker's core with its vitest runner), and once the patch is dropped hands -// both back to Dependabot. Left apart, Stryker would run a runner its core was not made for. +// The update pull request for a patched library moves it, and only it, to the new version. describe('bumpPackageJson', () => { - const pj = JSON.stringify({devDependencies: { - '@stryker-mutator/core': '10.0.0', '@stryker-mutator/vitest-runner': '10.0.0', 'hls.js': '^1.7.3', - }}, null, 2); + const pj = JSON.stringify({devDependencies: {'dashjs': '5.2.1', 'hls.js': '^1.7.3'}}, null, 2); - it('moves Stryker\'s core with its vitest runner', () => { - const out = JSON.parse(bumpPackageJson(pj, '@stryker-mutator/vitest-runner', '10.0.0', '10.1.0')); - expect(out.devDependencies['@stryker-mutator/vitest-runner']).toBe('10.1.0'); - expect(out.devDependencies['@stryker-mutator/core']).toBe('10.1.0'); - expect(out.devDependencies['hls.js']).toBe('^1.7.3'); - }); - - it('moves a library without companions alone, and keeps its range prefix', () => { + it('moves the library alone, and keeps its range prefix', () => { const out = JSON.parse(bumpPackageJson(pj, 'hls.js', '1.7.3', '1.8.0')); expect(out.devDependencies['hls.js']).toBe('^1.8.0'); - expect(out.devDependencies['@stryker-mutator/core']).toBe('10.0.0'); + expect(out.devDependencies['dashjs']).toBe('5.2.1'); }); - it('refuses when the library is not at the version its patch is cut against, or a companion is missing', () => { + it('refuses when the library is not at the version its patch is cut against', () => { expect(() => bumpPackageJson(pj, 'hls.js', '1.7.2', '1.8.0')).toThrow(/no "hls.js" at 1.7.2/); - const noCore = JSON.stringify({devDependencies: {'@stryker-mutator/vitest-runner': '10.0.0'}}); - expect(() => bumpPackageJson(noCore, '@stryker-mutator/vitest-runner', '10.0.0', '10.1.0')) - .toThrow(/no "@stryker-mutator\/core", which moves with/); }); }); @@ -196,14 +182,14 @@ describe('dropDependabotIgnores', () => { const file = path.join(dir, 'dependabot.yml'); fs.writeFileSync(file, [ ' ignore:', - ' - dependency-name: \'@stryker-mutator/core\'', - ' - dependency-name: \'@stryker-mutator/vitest-runner\'', + ' - dependency-name: \'dashjs\'', + ' - dependency-name: \'gif.js\'', ' - dependency-name: \'hls.js\'', ' # - dependency-name: \'commented\'', '', ].join('\n')); - expect(dropDependabotIgnores(['@stryker-mutator/vitest-runner', '@stryker-mutator/core', 'not-there'], file)) - .toEqual(['@stryker-mutator/core', '@stryker-mutator/vitest-runner']); + expect(dropDependabotIgnores(['gif.js', 'dashjs', 'not-there'], file)) + .toEqual(['dashjs', 'gif.js']); expect(fs.readFileSync(file, 'utf8')).toBe([ ' ignore:', ' - dependency-name: \'hls.js\'', diff --git a/tests/unit/strykerShards.test.mjs b/tests/unit/strykerShards.test.mjs deleted file mode 100644 index eda795da2..000000000 --- a/tests/unit/strykerShards.test.mjs +++ /dev/null @@ -1,97 +0,0 @@ -import fs from 'node:fs'; -import path from 'node:path'; -import {describe, expect, it} from 'vitest'; -import config, {AREAS, COMMAND_AREAS, PARTS, SHARDS, modulesOf, runnerOf, splitArea} from '../../stryker.config.mjs'; - -// The weekly mutation run's modules are in shards, each run by a job of its own -// (mutation-tests.yml), because all of them in one job were past its 240 minutes (#253). -// A module no shard lists is never mutated; a shard the workflow does not run is never -// reported; a module with no unit test can only "survive". - -const root = path.resolve(import.meta.dirname, '../..'); -const workflow = fs.readFileSync(path.join(root, '.github/workflows/mutation-tests.yml'), 'utf8'); - -describe('stryker.config.mjs: the shards', () => { - it('mutates every shard\'s modules when no shard is picked, as a local run does', () => { - expect(config.mutate).toEqual(modulesOf(process.env.STRYKER_SHARD)); - expect(modulesOf(undefined)).toEqual(Object.values(SHARDS).flat()); - expect(modulesOf('')).toHaveLength(modulesOf(undefined).length); - }); - - it('runs one shard\'s modules, and refuses a shard it does not have', () => { - expect(modulesOf('network-1')).toEqual(SHARDS['network-1']); - // An area's name is no shard: its modules are in its parts. - expect(() => modulesOf('network')).toThrow(/STRYKER_SHARD is network/); - expect(() => modulesOf('everything')).toThrow(/STRYKER_SHARD is everything/); - }); - - it('lists each module once, each a file of the repository', () => { - const all = modulesOf(undefined); - expect(new Set(all).size).toBe(all.length); - expect(all.filter((file) => !fs.existsSync(path.join(root, file)))).toEqual([]); - }); - - it('lists only modules a unit test imports', () => { - const tests = fs.readdirSync(path.join(root, 'tests/unit'), {recursive: true}) - .filter((file) => file.endsWith('.mjs')) - .map((file) => fs.readFileSync(path.join(root, 'tests/unit', file), 'utf8')).join('\n'); - const untested = modulesOf(undefined).filter((file) => !tests.includes(path.basename(file))); - expect(untested).toEqual([]); - }); - - it('cuts each area into its parts, each module in one, none empty', () => { - // One job an area ran out of its 240 minutes at 51-74% on CI, and no report came (#349). - for (const [area, modules] of Object.entries(AREAS)) { - const parts = Object.keys(SHARDS).filter((name) => name.startsWith(area + '-')); - expect(parts).toHaveLength(PARTS[area]); - expect(parts.flatMap((name) => SHARDS[name]).sort()).toEqual([...modules].sort()); - expect(parts.filter((name) => SHARDS[name].length === 0)).toEqual([]); - } - }); - - it('makes parts of about the same size, the same ones each time', () => { - const sizes = splitArea(AREAS.core, PARTS.core) - .map((group) => group.reduce((sum, file) => sum + fs.statSync(path.join(root, file)).size, 0)); - expect(Math.max(...sizes) / Math.min(...sizes)).toBeLessThan(1.25); - expect(splitArea(AREAS.core, PARTS.core)).toEqual(splitArea(AREAS.core, PARTS.core)); - }); - - it('reports a shard that ran out of its time: it ends cancelled, not failed', () => { - expect(workflow).toContain('needs.mutation.result == \'cancelled\''); - expect(workflow).toContain('timeout-minutes: 350'); - }); - - it('has the workflow run, and report, exactly these shards', () => { - const names = Object.keys(SHARDS); - expect(workflow).toContain(`shard: [${names.join(', ')}]`); - expect(workflow).toContain(`for shard in ${names.join(' ')}; do`); - expect(workflow).toContain('STRYKER_SHARD: ${{ matrix.shard }}'); - }); -}); - -// The vitest runner switches a mutant on inside the test worker; the mpv host's message loop -// runs only in the host process its tests start, so the host keeps the command runner, -// which hands the mutant to that process. Compared mutant by mutant on CI (2026-10-06), the -// host was the one module the vitest runner left untested where the command runner caught. -describe('stryker.config.mjs: the test runner a shard gets', () => { - it('runs the mpv host, alone, with the command runner and the whole suite a mutant', () => { - expect(COMMAND_AREAS).toEqual(['host']); - expect(AREAS.host).toEqual(['native-host/faststream-mpv-host.mjs']); - expect(Object.values(AREAS).flat().filter((m) => m === 'native-host/faststream-mpv-host.mjs')).toHaveLength(1); - const host = runnerOf('host-1'); - expect(host.testRunner).toBe('command'); - expect(host.coverageAnalysis).toBe('off'); - expect(host.commandRunner.command).toContain('vitest.mjs run'); - }); - - it('runs every other shard, and a run of everything, with the vitest runner and per-test coverage', () => { - for (const shard of [...Object.keys(SHARDS).filter((name) => !name.startsWith('host-')), undefined, '']) { - const runner = runnerOf(shard); - expect(runner.testRunner, String(shard)).toBe('vitest'); - expect(runner.coverageAnalysis).toBe('perTest'); - // Without it Stryker finds no runner under pnpm's layout. - expect(runner.plugins).toEqual(['@stryker-mutator/vitest-runner']); - } - expect(config.testRunner).toBe(runnerOf(process.env.STRYKER_SHARD).testRunner); - }); -}); diff --git a/tests/unit/typeChecked.test.mjs b/tests/unit/typeChecked.test.mjs index e23623325..b6af93712 100644 --- a/tests/unit/typeChecked.test.mjs +++ b/tests/unit/typeChecked.test.mjs @@ -196,8 +196,6 @@ const CHECKED = [ 'tools/hash-build.mjs', 'tools/launch-ff-fresh.mjs', 'tools/launch-ff.mjs', - 'tools/merge-mutation-reports.mjs', - 'tools/mutation-report.mjs', 'tools/newest-release.mjs', 'tools/rebuild.mjs', 'tools/recut-patch.mjs', diff --git a/tests/workflows/mutation-tests.test.sh b/tests/workflows/mutation-tests.test.sh deleted file mode 100644 index f227e6c9e..000000000 --- a/tests/workflows/mutation-tests.test.sh +++ /dev/null @@ -1,175 +0,0 @@ -#!/usr/bin/env bash -# mutation-tests.yml: the weekly "Mutation testing: week to " issue it opens when the -# unit tests missed mutants, the older issues it closes, the issues a week with every -# mutant caught closes, and the issue it opens when it fails. The step runs the real -# tools/mutation-report.mjs on a fixture report; the stub gh records what it creates, -# edits and closes. -source "$(dirname "$0")/lib.sh" - -here=$(mktemp -d) -trap 'rm -rf "$here"' EXIT -issue_step=$here/issue.sh -report_step=$here/report.sh -step_script mutation-tests.yml "Open, update or close the week's issue" > "$issue_step" || exit 1 -step_script mutation-tests.yml "Report this workflow's own failure" > "$report_step" || exit 1 - -mkdir -p "$here/bin" -cat > "$here/bin/gh" <<'EOF' -#!/usr/bin/env bash -set -euo pipefail -jqf='' -args=("$@") -for ((i = 0; i < ${#args[@]}; i++)); do - if [ "${args[i]}" = --jq ]; then jqf=${args[i + 1]-}; fi -done -logbody() { - while [ $# -gt 0 ]; do - if [ "$1" = --body-file ]; then echo '--- body:'; cat "$2"; echo '--- end body'; fi - shift - done -} -case "$1 $2" in - 'api --paginate') - [ "$3" = "repos/$GH_REPO/issues?state=all&per_page=100" ] || { echo "stub gh: unexpected api path $3" >&2; exit 2; } - jq -r "$jqf" "$FIX/issues.json" ;; - 'issue create') - { printf 'CREATE'; printf ' [%s]' "${@:3}"; printf '\n'; logbody "$@"; } >> "$LOG" - echo "https://github.com/$GH_REPO/issues/99" ;; - 'issue edit') - { printf 'EDIT'; printf ' [%s]' "${@:3}"; printf '\n'; logbody "$@"; } >> "$LOG" ;; - 'issue close') - { printf 'CLOSE'; printf ' [%s]' "${@:3}"; printf '\n'; } >> "$LOG" ;; - 'issue comment') - { printf 'COMMENT'; printf ' [%s]' "${@:3}"; printf '\n'; logbody "$@"; } >> "$LOG" ;; - 'issue list') - [[ " $* " == *' --state open --limit 200 '* ]] || { echo "stub gh: not a list of all open issues: $*" >&2; exit 2; } - jq -r "$jqf" "$FIX/open.json" ;; - *) - echo "stub gh: unexpected call: $*" >&2; exit 2 ;; -esac -EOF -chmod +x "$here/bin/gh" - -export GH_TOKEN=stub GH_REPO='Nawid3333/FastStream' OWNER='Nawid3333' PREFIX='Mutation testing: week to ' -export RUN_URL='https://github.com/Nawid3333/FastStream/actions/runs/1' -TITLE='Mutation tests workflow failed' -export -n TITLE -check "the job's env: gives the prefix" contains "$WORKFLOWS_DIR/mutation-tests.yml" "PREFIX: '$PREFIX'" -check "the report step's env: gives the title" contains "$WORKFLOWS_DIR/mutation-tests.yml" "TITLE: '$TITLE'" - -today=$(date -u +%F) -bot='{"login":"github-actions[bot]"}' -human='{"login":"Nawid3333"}' -script="$(cd "$(dirname "$0")/../.." && pwd)/tools/mutation-report.mjs" - -# A mutant of Stryker's report. -m() { printf '{"status":"%s","mutatorName":"%s","replacement":"%s","location":{"start":{"line":%s,"column":1}}}' "$1" "$2" "$3" "$4"; } -missing="{\"files\":{\"chrome/player/utils/StreamPick.mjs\":{\"mutants\":[$(m Killed EqualityOperator 'a <= b' 3),$(m Survived ConditionalExpression true 9)]},\"chrome/background/DownloadFilename.mjs\":{\"mutants\":[$(m NoCoverage StringLiteral '' 20)]}}}" -allcaught="{\"files\":{\"chrome/player/utils/StreamPick.mjs\":{\"mutants\":[$(m Killed EqualityOperator 'a <= b' 3),$(m Timeout BlockStatement '{}' 4)]}}}" - -# run [open json]: the step, in a folder holding -# the report and the real report script, as in the job's checkout. -run() { - echo "$1" - export FIX="$here/fix" RUNNER_TEMP="$here/fix/tmp" LOG="$here/fix/log" - rm -rf "$FIX" - mkdir -p "$RUNNER_TEMP" "$FIX/work/reports/mutation" "$FIX/work/tools" - : > "$LOG" - cp "$script" "$FIX/work/tools/" - printf '%s' "$3" > "$FIX/work/reports/mutation/mutation.json" - printf '%s' "$4" > "$FIX/issues.json" - printf '%s' "${5:-[]}" > "$FIX/open.json" - ( - cd "$FIX/work" || exit 9 - if [ "$2" = "$report_step" ]; then export TITLE; fi - PATH="$here/bin:$PATH" run_step "$2" - ) > "$FIX/out" 2>&1 - status=$? -} - -run 's1 mutants not caught -> opens this week'"'"'s issue, closes last week'"'"'s' "$issue_step" "$missing" \ - "[{\"number\":5,\"state\":\"open\",\"title\":\"${PREFIX}2026-09-01\",\"user\":$bot},{\"number\":3,\"state\":\"closed\",\"title\":\"${PREFIX}2026-08-25\",\"user\":$bot},{\"number\":6,\"state\":\"open\",\"title\":\"${PREFIX}notes\",\"user\":$human},{\"number\":8,\"state\":\"open\",\"title\":\"${PREFIX}2026-09-08\",\"user\":$bot,\"pull_request\":{}}]" -check 'succeeds' test "$status" -eq 0 -check "opens \"${PREFIX}$today\", assigned to the owner" contains "$LOG" "CREATE [--title] [${PREFIX}$today] [--assignee] [Nawid3333]" -check 'mentions the owner and the count' contains "$LOG" "@Nawid3333 The unit tests did not catch 2 of this week's mutants" -check 'links the run' contains "$LOG" "Run: $RUN_URL" -check 'lists the survivor' contains "$LOG" '- line 9: survived - ConditionalExpression: `true`' -check 'and the line no test reaches' contains "$LOG" '- line 20: no test reaches it - StringLiteral: `(removed)`' -check "closes last week's #5, pointing at the new one" contains "$LOG" "CLOSE [5] [--reason] [completed] [--comment] [#99 lists the week to $today.]" -check 'leaves closed #3 alone' lacks "$LOG" 'CLOSE [3]' -check "leaves a person's issue alone" lacks "$LOG" 'CLOSE [6]' -check 'leaves a pull request alone' lacks "$LOG" 'CLOSE [8]' - -run 's2 run again the same day -> updates today'"'"'s issue' "$issue_step" "$missing" \ - "[{\"number\":7,\"state\":\"open\",\"title\":\"${PREFIX}$today\",\"user\":$bot},{\"number\":5,\"state\":\"open\",\"title\":\"${PREFIX}2026-09-01\",\"user\":$bot}]" -check 'succeeds' test "$status" -eq 0 -check 'opens nothing' lacks "$LOG" 'CREATE' -check "updates #7" contains "$LOG" 'EDIT [7] [--body-file]' -check 'closes #5, pointing at #7' contains "$LOG" "CLOSE [5] [--reason] [completed] [--comment] [#7 lists the week to $today.]" -check 'leaves #7 open' lacks "$LOG" 'CLOSE [7]' - -run 's3 every mutant caught -> opens nothing, closes the open one' "$issue_step" "$allcaught" \ - "[{\"number\":5,\"state\":\"open\",\"title\":\"${PREFIX}2026-09-01\",\"user\":$bot},{\"number\":6,\"state\":\"open\",\"title\":\"${PREFIX}notes\",\"user\":$human}]" -check 'succeeds' test "$status" -eq 0 -check 'opens nothing' lacks "$LOG" 'CREATE' -check 'closes #5, saying why' contains "$LOG" "CLOSE [5] [--reason] [completed] [--comment] [The unit tests caught every mutant in the week to $today: $RUN_URL]" -check "leaves a person's issue alone" lacks "$LOG" 'CLOSE [6]' - -export MISSING_SHARDS=host-1 -run 's3b every mutant of the reports caught, but a shard wrote none -> closes nothing' "$issue_step" "$allcaught" \ - "[{\"number\":5,\"state\":\"open\",\"title\":\"${PREFIX}2026-09-01\",\"user\":$bot}]" -check 'succeeds' test "$status" -eq 0 -check 'opens nothing' lacks "$LOG" 'CREATE' -check 'leaves #5 open: the missing shard said nothing of its mutants' lacks "$LOG" 'CLOSE [5]' -check 'says which shard wrote none' contains "$FIX/out" 'no report from: host-1' -run 's3c mutants not caught, and a shard wrote none -> still opens the issue' "$issue_step" "$missing" '[]' -check 'succeeds' test "$status" -eq 0 -check 'opens the week'"'"'s issue' contains "$LOG" "CREATE [--title] [${PREFIX}$today]" -export -n MISSING_SHARDS -unset MISSING_SHARDS - -# The report job's merge: the shards' reports from their artifacts, one each, into one. -merge_step=$here/merge.sh -step_script mutation-tests.yml "Put the shards' reports together" > "$merge_step" || exit 1 -merge() { - echo "$1" - export FIX="$here/fix" GITHUB_ENV="$here/fix/env" - rm -rf "$FIX" - mkdir -p "$FIX/work/tools" - : > "$GITHUB_ENV" - cp "$script" "$(dirname "$script")/merge-mutation-reports.mjs" "$FIX/work/tools/" - shift - while [ $# -gt 0 ]; do - mkdir -p "$FIX/work/shards/mutation-reports-$1" - printf '%s' "$2" > "$FIX/work/shards/mutation-reports-$1/mutation.json" - shift 2 - done - (cd "$FIX/work" && run_step "$merge_step") > "$FIX/out" 2>&1 - status=$? -} -network="{\"files\":{\"chrome/player/network/FetchLoader.mjs\":{\"mutants\":[$(m Survived ConditionalExpression true 4)]}}}" -merge 's6 two shards of four -> one report of both, the others named missing' core-1 "$missing" network-1 "$network" -check 'succeeds' test "$status" -eq 0 -check 'names the missing shards' contains "$GITHUB_ENV" 'MISSING_SHARDS=tools-1 host-1' -check 'the report has both shards'"'"' files' contains "$FIX/work/reports/mutation/mutation.json" 'chrome/player/network/FetchLoader.mjs' -check '... and the first shard'"'"'s' contains "$FIX/work/reports/mutation/mutation.json" 'chrome/player/utils/StreamPick.mjs' -merge 's7 every shard -> none missing' core-1 "$missing" network-1 "$network" tools-1 '{"files":{}}' host-1 '{"files":{}}' -check 'succeeds' test "$status" -eq 0 -check 'names none missing' contains "$GITHUB_ENV" 'MISSING_SHARDS=' -check '... and no shard' lacks "$GITHUB_ENV" 'MISSING_SHARDS=core' -merge 's8 no shard wrote a report -> no report, all four missing' -check 'succeeds' test "$status" -eq 0 -check 'names all four' contains "$GITHUB_ENV" 'MISSING_SHARDS=core-1 network-1 tools-1 host-1' -check 'writes no report' test ! -e "$FIX/work/reports/mutation/mutation.json" - -run 's4 failure report, none open -> opens the failure issue' "$report_step" '{}' '[]' '[{"title":"Other"}]' -check 'succeeds' test "$status" -eq 0 -check 'opens "Mutation tests workflow failed", assigned to the owner' contains "$LOG" \ - 'CREATE [--title] [Mutation tests workflow failed] [--assignee] [Nawid3333]' - -run 's5 failure report, already open -> a comment on it' "$report_step" '{}' '[]' '[{"number":12,"title":"Mutation tests workflow failed"}]' -check 'succeeds' test "$status" -eq 0 -check 'comments on the open one' contains "$LOG" 'COMMENT [12] [--body-file]' -check 'creates nothing' lacks "$LOG" 'CREATE' - -finish diff --git a/tools/check-patched-updates.mjs b/tools/check-patched-updates.mjs index 9d43ddc5f..c8fcc16a6 100644 --- a/tools/check-patched-updates.mjs +++ b/tools/check-patched-updates.mjs @@ -21,16 +21,6 @@ import {fileURLToPath} from 'node:url'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); -/** - * Packages that must stay at a patched library's exact version, by the library's name. They - * move with it: its update pull request bumps them too (tools/recut-patch.mjs), and - * Dependabot leaves them alone while the library is patched (.github/dependabot.yml), where - * it would bump them alone. @stryker-mutator/vitest-runner requires the @stryker-mutator/core - * of its own version, exactly (its peerDependencies). - * @type {Object} - */ -export const LOCKSTEP = {'@stryker-mutator/vitest-runner': ['@stryker-mutator/core']}; - /** * @param {string} yaml - pnpm-workspace.yaml. * @return {Array<{name: string, version: string}>} The patched libraries. diff --git a/tools/merge-mutation-reports.mjs b/tools/merge-mutation-reports.mjs deleted file mode 100644 index 48e51287e..000000000 --- a/tools/merge-mutation-reports.mjs +++ /dev/null @@ -1,22 +0,0 @@ -// @ts-check -// mutation-tests.yml's report job: the shards' reports, as their artifacts were downloaded -// (shards/mutation-reports-/mutation.json), put together into the one report the -// summary and the week's issue read (reports/mutation/mutation.json). No arguments: the -// paths are the job's own, and a shard without a report is left out (the step names it). -import fs from 'node:fs'; -import path from 'node:path'; -import {merge} from './mutation-report.mjs'; - -const reports = []; -for (const artifact of fs.readdirSync('shards').sort()) { - let text; - try { - text = fs.readFileSync(path.join('shards', artifact, 'mutation.json'), 'utf8'); - } catch (e) { - if (e.code === 'ENOENT') continue; - throw e; - } - reports.push(JSON.parse(text)); -} -fs.mkdirSync('reports/mutation', {recursive: true}); -fs.writeFileSync('reports/mutation/mutation.json', JSON.stringify(merge(reports))); diff --git a/tools/mutation-report.mjs b/tools/mutation-report.mjs deleted file mode 100644 index b70467669..000000000 --- a/tools/mutation-report.mjs +++ /dev/null @@ -1,149 +0,0 @@ -// @ts-check -// Turns Stryker's report (reports/mutation/mutation.json) into what mutation-tests.yml -// shows: a table per file for the run's summary, and the body of the week's issue, which -// lists the mutants the unit tests did not catch. -// -// node tools/mutation-report.mjs summary -// node tools/mutation-report.mjs issue -// node tools/mutation-report.mjs count -// -// merge() puts the shards' reports together (tools/merge-mutation-reports.mjs). -// -// "Not caught" is Survived (the tests ran and passed) and NoCoverage (no test reached it). -// Killed and Timeout count as caught, as Stryker counts them. - -import fs from 'node:fs'; -import * as url from 'node:url'; - -const CAUGHT = new Set(['Killed', 'Timeout']); -const MISSED = new Set(['Survived', 'NoCoverage']); -const LISTED = 100; - -/** - * Each file's mutants, by status. - * @param {Object} report - Stryker's mutation-testing report. - * @return {Array<{file: string, total: number, caught: number, missed: number, score: number}>} - * Sorted by file; score is caught in percent of the mutants that ran, one decimal. - */ -export function perFile(report) { - return Object.entries(report.files || {}).sort(([a], [b]) => a.localeCompare(b)).map(([file, {mutants}]) => { - const caught = mutants.filter((m) => CAUGHT.has(m.status)).length; - const missed = mutants.filter((m) => MISSED.has(m.status)).length; - const ran = caught + missed; - return {file, total: mutants.length, caught, missed, score: ran ? Math.round(caught * 1000 / ran) / 10 : 100}; - }); -} - -/** - * Text from a report, safe in a table cell or inline code: one line, no pipe, no backtick. - * @param {*} value - * @return {string} - */ -function cell(value) { - return String(value ?? '').replace(/\s+/g, ' ').replace(/\\/g, '\\\\').replace(/\|/g, '\\|').replace(/`/g, '\''); -} - -/** - * The run summary: one row per file and a total. - * @param {Object} report - * @return {string} Markdown. - */ -export function summary(report) { - const rows = perFile(report); - const total = rows.reduce((t, r) => ({total: t.total + r.total, caught: t.caught + r.caught, missed: t.missed + r.missed}), - {total: 0, caught: 0, missed: 0}); - const ran = total.caught + total.missed; - return [ - '### Mutation testing', - '', - 'Caught: the unit tests failed with the change (or timed out). Not caught: they passed, or none reached it.', - '', - '| File | Mutants | Caught | Not caught | Score |', - '| --- | --- | --- | --- | --- |', - ...rows.map((r) => `| ${cell(r.file)} | ${r.total} | ${r.caught} | ${r.missed} | ${r.score}% |`), - `| **All** | ${total.total} | ${total.caught} | ${total.missed} | ${ran ? Math.round(total.caught * 1000 / ran) / 10 : 100}% |`, - '', - ].join('\n'); -} - -/** - * The mutants not caught, by file and line. - * @param {Object} report - * @return {Array<{file: string, line: number, status: string, mutator: string, replacement: string}>} - */ -export function missed(report) { - const out = []; - for (const [file, {mutants}] of Object.entries(report.files || {})) { - for (const m of mutants) { - if (MISSED.has(m.status)) { - out.push({file, line: m.location?.start?.line ?? 0, status: m.status, mutator: m.mutatorName, replacement: m.replacement ?? ''}); - } - } - } - return out.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line); -} - -/** - * The week's issue: what was not caught, the first LISTED of it by file. - * @param {Object} report - * @param {string} owner - Who to @mention. - * @param {string} runUrl - The run, whose artifact has the full report. - * @return {string} Markdown. - */ -export function issueBody(report, owner, runUrl) { - const list = missed(report); - const shown = list.slice(0, LISTED); - const lines = [ - `@${owner} The unit tests did not catch ${list.length} of this week's mutants: changes to the code they still passed, or that no test reached. Each is a place where a fix could ship without a test that fails without it.`, - '', - `Run: ${runUrl} (its mutation-reports artifact has the full report, kept 30 days).`, - '', - summary(report), - `### Not caught${list.length > LISTED ? ` (the first ${LISTED} of ${list.length})` : ''}`, - ]; - /** @type {string|null} */ - let file = null; - for (const m of shown) { - if (m.file !== file) { - file = m.file; - lines.push('', `**${cell(file)}**`, ''); - } - lines.push(`- line ${m.line}: ${m.status === 'NoCoverage' ? 'no test reaches it' : 'survived'} - ${cell(m.mutator)}: \`${cell(m.replacement) || '(removed)'}\``); - } - lines.push('', 'Next week\'s issue replaces this one; a week with every mutant caught closes it.', ''); - return lines.join('\n'); -} - -/** - * One report of several: mutation-tests.yml runs the modules in shards, a job each, and - * each writes its own report (stryker.config.mjs, SHARDS). - * @param {Object[]} reports - Stryker's reports, of disjoint modules. - * @return {Object} The first report, with every report's files. - */ -export function merge(reports) { - const files = new Map(); - for (const report of reports) { - for (const [file, entry] of Object.entries(report.files || {})) { - if (files.has(file)) { - throw new Error(`${file} is in two reports: each module belongs to one shard`); - } - files.set(file, entry); - } - } - return {...(reports[0] || {}), files: Object.fromEntries(files)}; -} - -if (process.argv[1] && import.meta.url === url.pathToFileURL(process.argv[1]).href) { - const [file, what, owner, runUrl] = process.argv.slice(2); - const report = JSON.parse(fs.readFileSync(file, 'utf8')); - if (what === 'summary') { - process.stdout.write(summary(report)); - } else if (what === 'issue') { - process.stdout.write(issueBody(report, owner, runUrl)); - } else if (what === 'count') { - process.stdout.write(String(missed(report).length) + '\n'); - } else { - console.error('usage: mutation-report.mjs summary|issue |count'); - process.exit(2); - } -} diff --git a/tools/recut-patch.mjs b/tools/recut-patch.mjs index 096ba2724..ecab0d106 100644 --- a/tools/recut-patch.mjs +++ b/tools/recut-patch.mjs @@ -47,7 +47,7 @@ import path from 'node:path'; import * as url from 'node:url'; import {spawnSync} from 'node:child_process'; -import {LOCKSTEP, patchedDependencies} from './check-patched-updates.mjs'; +import {patchedDependencies} from './check-patched-updates.mjs'; const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); // This repository, always. An environment variable could point it elsewhere until 2026-10-06; @@ -618,7 +618,7 @@ async function main() { /** * Takes names off .github/dependabot.yml's ignore list, so Dependabot updates them again: - * a library whose patch is dropped, and the packages that moved with it (LOCKSTEP). + * a library whose patch is dropped. * @param {string[]} names * @param {string} [file] - The Dependabot config. * @return {string[]} The names that were on the list. @@ -636,8 +636,7 @@ function dropDependabotIgnores(names, file = path.join(root, '.github/dependabot } /** - * package.json with a library moved from one version to another, and the packages that must - * stay at its version with it (LOCKSTEP). + * package.json with a library moved from one version to another. * @param {string} text - package.json. * @param {string} pkg * @param {string} from @@ -650,13 +649,7 @@ function bumpPackageJson(text, pkg, from, to) { // version's tag. const verRe = new RegExp(`("${esc(pkg)}":\\s*"(?:[~^]?|(?:github:|git\\+|git:)[^#"]+#v?))${esc(from)}"`); if (!verRe.test(text)) throw new Error(`package.json has no "${pkg}" at ${from}`); - let out = text.replace(verRe, `$1${to}"`); - for (const companion of LOCKSTEP[pkg] || []) { - const companionRe = new RegExp(`("${esc(companion)}":\\s*")[^"]+"`); - if (!companionRe.test(out)) throw new Error(`package.json has no "${companion}", which moves with ${pkg}`); - out = out.replace(companionRe, `$1${to}"`); - } - return out; + return text.replace(verRe, `$1${to}"`); } function applyUpdate(opts, cur, result, work) { @@ -694,8 +687,8 @@ function applyUpdate(opts, cur, result, work) { fs.copyFileSync(path.join(work, 'merged', f.file), path.join(edit, f.file)); } if (result.files.every((f) => f.landed)) { - // Dependabot takes the library back, and what moves with it. - const handedBack = dropDependabotIgnores([pkg, ...(LOCKSTEP[pkg] || [])]); + // Dependabot takes the library back. + const handedBack = dropDependabotIgnores([pkg]); console.log(`Every change has landed in ${pkg} ${to}: the patch is dropped` + (handedBack.length ? `, and Dependabot updates ${handedBack.join(' and ')} again (.github/dependabot.yml)` : '') + `. Remove any \`patched: true\` marks for ${pkg} in tools/sync-vendor.mjs.`);