diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 9d22f618d81c1..0000000000000 --- a/.eslintignore +++ /dev/null @@ -1,18 +0,0 @@ -test/assets/modernizr.js -/tests/third_party/ -/packages/*/lib/ -*.js -/packages/playwright-core/src/generated/* -/packages/playwright-core/src/third_party/ -/packages/playwright-core/types/* -/packages/playwright-ct-core/src/generated/* -/index.d.ts -node_modules/ -**/*.d.ts -output/ -test-results/ -/tests/components/ -/tests/installation/fixture-scripts/ -DEPS -.cache/ -/utils/ diff --git a/.eslintrc-with-ts-config.js b/.eslintrc-with-ts-config.js deleted file mode 100644 index b06ec001951bc..0000000000000 --- a/.eslintrc-with-ts-config.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - extends: "./.eslintrc.js", - parserOptions: { - ecmaVersion: 9, - sourceType: "module", - project: "./tsconfig.json", - }, - rules: { - "@typescript-eslint/no-base-to-string": "error", - "@typescript-eslint/no-unnecessary-boolean-literal-compare": 2, - }, - parserOptions: { - project: "./tsconfig.json" - }, -}; diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index e71a4ffd09bf9..0000000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,137 +0,0 @@ -module.exports = { - parser: "@typescript-eslint/parser", - plugins: ["@typescript-eslint", "notice"], - parserOptions: { - ecmaVersion: 9, - sourceType: "module", - }, - extends: [ - "plugin:react/recommended", - "plugin:react-hooks/recommended" - ], - - settings: { - react: { version: "18" } - }, - - /** - * ESLint rules - * - * All available rules: http://eslint.org/docs/rules/ - * - * Rules take the following form: - * "rule-name", [severity, { opts }] - * Severity: 2 == error, 1 == warning, 0 == off. - */ - rules: { - "@typescript-eslint/no-unused-vars": [2, {args: "none"}], - "@typescript-eslint/consistent-type-imports": [2, {disallowTypeAnnotations: false}], - /** - * Enforced rules - */ - // syntax preferences - "object-curly-spacing": ["error", "always"], - "quotes": [2, "single", { - "avoidEscape": true, - "allowTemplateLiterals": true - }], - "jsx-quotes": [2, "prefer-single"], - "no-extra-semi": 2, - "@typescript-eslint/semi": [2], - "comma-style": [2, "last"], - "wrap-iife": [2, "inside"], - "spaced-comment": [2, "always", { - "markers": ["*"] - }], - "eqeqeq": [2], - "accessor-pairs": [2, { - "getWithoutSet": false, - "setWithoutGet": false - }], - "brace-style": [2, "1tbs", {"allowSingleLine": true}], - "curly": [2, "multi-or-nest", "consistent"], - "new-parens": 2, - "arrow-parens": [2, "as-needed"], - "prefer-const": 2, - "quote-props": [2, "consistent"], - "nonblock-statement-body-position": [2, "below"], - - // anti-patterns - "no-var": 2, - "no-with": 2, - "no-multi-str": 2, - "no-caller": 2, - "no-implied-eval": 2, - "no-labels": 2, - "no-new-object": 2, - "no-octal-escape": 2, - "no-self-compare": 2, - "no-shadow-restricted-names": 2, - "no-cond-assign": 2, - "no-debugger": 2, - "no-dupe-keys": 2, - "no-duplicate-case": 2, - "no-empty-character-class": 2, - "no-unreachable": 2, - "no-unsafe-negation": 2, - "radix": 2, - "valid-typeof": 2, - "no-implicit-globals": [2], - "no-unused-expressions": [2, { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true}], - "no-proto": 2, - - // es2015 features - "require-yield": 2, - "template-curly-spacing": [2, "never"], - - // spacing details - "space-infix-ops": 2, - "space-in-parens": [2, "never"], - "array-bracket-spacing": [2, "never"], - "comma-spacing": [2, { "before": false, "after": true }], - "keyword-spacing": [2, "always"], - "space-before-function-paren": [2, { - "anonymous": "never", - "named": "never", - "asyncArrow": "always" - }], - "no-whitespace-before-property": 2, - "keyword-spacing": [2, { - "overrides": { - "if": {"after": true}, - "else": {"after": true}, - "for": {"after": true}, - "while": {"after": true}, - "do": {"after": true}, - "switch": {"after": true}, - "return": {"after": true} - } - }], - "arrow-spacing": [2, { - "after": true, - "before": true - }], - "@typescript-eslint/func-call-spacing": 2, - "@typescript-eslint/type-annotation-spacing": 2, - - // file whitespace - "no-multiple-empty-lines": [2, {"max": 2, "maxEOF": 0}], - "no-mixed-spaces-and-tabs": 2, - "no-trailing-spaces": 2, - "linebreak-style": [ process.platform === "win32" ? 0 : 2, "unix" ], - "indent": [2, 2, { "SwitchCase": 1, "CallExpression": {"arguments": 2}, "MemberExpression": 2 }], - "key-spacing": [2, { - "beforeColon": false - }], - "eol-last": 2, - - // copyright - "notice/notice": [2, { - "mustMatch": "Copyright", - "templateFile": require("path").join(__dirname, "utils", "copyright.js"), - }], - - // react - "react/react-in-jsx-scope": 0 - } -}; diff --git a/.github/workflows/infra.yml b/.github/workflows/infra.yml index 1d52ddb96d41d..bb488009ff0a4 100644 --- a/.github/workflows/infra.yml +++ b/.github/workflows/infra.yml @@ -35,7 +35,7 @@ jobs: exit 1 fi - name: Audit prod NPM dependencies - run: npm audit --omit dev + run: node utils/check_audit.js lint-snippets: name: "Lint snippets" runs-on: ubuntu-latest diff --git a/.github/workflows/roll_browser_into_playwright.yml b/.github/workflows/roll_browser_into_playwright.yml index e24d015cf8a2c..88fae9c031905 100644 --- a/.github/workflows/roll_browser_into_playwright.yml +++ b/.github/workflows/roll_browser_into_playwright.yml @@ -3,9 +3,21 @@ name: Roll Browser into Playwright on: repository_dispatch: types: [roll_into_pw] + workflow_dispatch: + inputs: + browser: + description: 'Browser name, e.g. chromium' + required: true + type: string + revision: + description: 'Browser revision without v prefix, e.g. 1234' + required: true + type: string env: ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + BROWSER: ${{ github.event.client_payload.browser || github.event.inputs.browser }} + REVISION: ${{ github.event.client_payload.revision || github.event.inputs.revision }} permissions: contents: write @@ -24,19 +36,19 @@ jobs: run: npx playwright install-deps - name: Roll to new revision run: | - ./utils/roll_browser.js ${{ github.event.client_payload.browser }} ${{ github.event.client_payload.revision }} + ./utils/roll_browser.js $BROWSER $REVISION npm run build - name: Prepare branch id: prepare-branch run: | - BRANCH_NAME="roll-into-pw-${{ github.event.client_payload.browser }}/${{ github.event.client_payload.revision }}" + BRANCH_NAME="roll-into-pw-${BROWSER}/${REVISION}" echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT git config --global user.name github-actions git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com git checkout -b "$BRANCH_NAME" git add . - git commit -m "feat(${{ github.event.client_payload.browser }}): roll to r${{ github.event.client_payload.revision }}" - git push origin $BRANCH_NAME + git commit -m "feat(${BROWSER}): roll to r${REVISION}" + git push origin $BRANCH_NAME --force - name: Create Pull Request uses: actions/github-script@v7 with: @@ -47,7 +59,7 @@ jobs: repo: 'playwright', head: 'microsoft:${{ steps.prepare-branch.outputs.BRANCH_NAME }}', base: 'main', - title: 'feat(${{ github.event.client_payload.browser }}): roll to r${{ github.event.client_payload.revision }}', + title: 'feat(${{ env.BROWSER }}): roll to r${{ env.REVISION }}', }); await github.rest.issues.addLabels({ owner: 'microsoft', diff --git a/.github/workflows/tests_bidi.yml b/.github/workflows/tests_bidi.yml index 6be824869aac7..f2e38765f7eca 100644 --- a/.github/workflows/tests_bidi.yml +++ b/.github/workflows/tests_bidi.yml @@ -7,7 +7,8 @@ on: - main paths: - .github/workflows/tests_bidi.yml - - packages/playwright-core/src/server/bidi/* + - packages/playwright-core/src/server/bidi/** + - tests/bidi/** schedule: # Run every day at midnight - cron: '0 0 * * *' diff --git a/.github/workflows/tests_primary.yml b/.github/workflows/tests_primary.yml index b8ec84ee56773..7d2226523107c 100644 --- a/.github/workflows/tests_primary.yml +++ b/.github/workflows/tests_primary.yml @@ -23,6 +23,7 @@ env: # Force terminal colors. @see https://www.npmjs.com/package/colors FORCE_COLOR: 1 ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + DEBUG_GIT_COMMIT_INFO: 1 jobs: test_linux: @@ -165,6 +166,7 @@ jobs: runs-on: ubuntu-latest env: PWTEST_BOT_NAME: "vscode-extension" + DEBUG_GIT_COMMIT_INFO: "" steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 diff --git a/.gitignore b/.gitignore index 1f3b9a7a72959..8e41e318108ae 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,4 @@ test-results .cache/ .eslintcache playwright.env -firefox +/firefox/ diff --git a/FILING_ISSUES.md b/FILING_ISSUES.md new file mode 100644 index 0000000000000..b699cd2e50440 --- /dev/null +++ b/FILING_ISSUES.md @@ -0,0 +1,35 @@ +# How to File a Bug Report That Actually Gets Resolved + +Make sure you’re on the latest Playwright release before filing. Check existing GitHub issues to avoid duplicates. + +## Use the Template + +Follow the **Bug Report** template. It guides you step-by-step: + +- Fill it out thoroughly. +- Clearly list the steps needed to reproduce the bug. +- Provide what you expected to see versus what happened in reality. +- Include system info from `npx envinfo --preset playwright`. + +## Keep Your Repro Minimal + +We can't parse your entire code base. Reduce it down to the absolute essentials: + +- Start a fresh project (`npm init playwright@latest new-project`). +- Add only the code/DOM needed to show the problem. +- Only use major frameworks if necessary (React, Angular, static HTTP server, etc.). +- Avoid adding extra libraries unless absolutely necessary. Note that we won't install any suspect dependencies. + +## Why This Matters +- Most issues that lack a repro turn out to be misconfigurations or usage errors. +- We can't fix problems if we can’t reproduce them ourselves. +- We can’t debug entire private projects or handle sensitive credentials. +- Each confirmed bug will have a test in our repo, so your repro must be as clean as possible. + +## More Help + +- [Stack Overflow’s Minimal Reproducible Example Guide](https://stackoverflow.com/help/minimal-reproducible-example) +- [Playwright Debugging Tools](https://playwright.dev/docs/debug) + +## Bottom Line +A well-isolated bug speeds up verification and resolution. Minimal, public repro or it’s unlikely we can assist. diff --git a/README.md b/README.md index 013ac177cf09f..3b96f5f48b19b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 🎭 Playwright -[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) [![Chromium version](https://img.shields.io/badge/chromium-133.0.6943.16-blue.svg?logo=google-chrome)](https://www.chromium.org/Home) [![Firefox version](https://img.shields.io/badge/firefox-134.0-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/) [![WebKit version](https://img.shields.io/badge/webkit-18.2-blue.svg?logo=safari)](https://webkit.org/) [![Join Discord](https://img.shields.io/badge/join-discord-infomational)](https://aka.ms/playwright/discord) +[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) [![Chromium version](https://img.shields.io/badge/chromium-134.0.6998.35-blue.svg?logo=google-chrome)](https://www.chromium.org/Home) [![Firefox version](https://img.shields.io/badge/firefox-135.0-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/) [![WebKit version](https://img.shields.io/badge/webkit-18.4-blue.svg?logo=safari)](https://webkit.org/) [![Join Discord](https://img.shields.io/badge/join-discord-infomational)](https://aka.ms/playwright/discord) ## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright) @@ -8,9 +8,9 @@ Playwright is a framework for Web Testing and Automation. It allows testing [Chr | | Linux | macOS | Windows | | :--- | :---: | :---: | :---: | -| Chromium 133.0.6943.16 | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| WebKit 18.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Firefox 134.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Chromium 134.0.6998.35 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| WebKit 18.4 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Firefox 135.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | Headless execution is supported for all browsers on all platforms. Check out [system requirements](https://playwright.dev/docs/intro#system-requirements) for details. diff --git a/browser_patches/firefox/UPSTREAM_CONFIG.sh b/browser_patches/firefox/UPSTREAM_CONFIG.sh index 7956cc114d58b..2b6979cfaba4a 100644 --- a/browser_patches/firefox/UPSTREAM_CONFIG.sh +++ b/browser_patches/firefox/UPSTREAM_CONFIG.sh @@ -1,3 +1,3 @@ REMOTE_URL="https://github.com/mozilla/gecko-dev" BASE_BRANCH="release" -BASE_REVISION="bc78b98043438d8ee2727a483b6e10dedfda883f" +BASE_REVISION="4764531b2bb14867dde520d74f6a3c88690e0751" diff --git a/browser_patches/firefox/juggler/TargetRegistry.js b/browser_patches/firefox/juggler/TargetRegistry.js index c40c831d01257..fb6280faebf5b 100644 --- a/browser_patches/firefox/juggler/TargetRegistry.js +++ b/browser_patches/firefox/juggler/TargetRegistry.js @@ -384,6 +384,7 @@ class PageTarget { this._linkedBrowser = tab.linkedBrowser; this._browserContext = browserContext; this._viewportSize = undefined; + this._zoom = 1; this._initialDPPX = this._linkedBrowser.browsingContext.overrideDPPX; this._url = 'about:blank'; this._openerId = opener ? opener.id() : undefined; @@ -393,7 +394,7 @@ class PageTarget { this._videoRecordingInfo = undefined; this._screencastRecordingInfo = undefined; this._dialogs = new Map(); - this.forcedColors = 'no-override'; + this.forcedColors = 'none'; this.disableCache = false; this.mediumOverride = ''; this.crossProcessCookie = { @@ -496,6 +497,7 @@ class PageTarget { this.updateUserAgent(browsingContext); this.updatePlatform(browsingContext); this.updateDPPXOverride(browsingContext); + this.updateZoom(browsingContext); this.updateEmulatedMedia(browsingContext); this.updateColorSchemeOverride(browsingContext); this.updateReducedMotionOverride(browsingContext); @@ -534,7 +536,16 @@ class PageTarget { } updateDPPXOverride(browsingContext = undefined) { - (browsingContext || this._linkedBrowser.browsingContext).overrideDPPX = this._browserContext.deviceScaleFactor || this._initialDPPX; + browsingContext ||= this._linkedBrowser.browsingContext; + const dppx = this._zoom * (this._browserContext.deviceScaleFactor || this._initialDPPX); + browsingContext.overrideDPPX = dppx; + } + + async updateZoom(browsingContext = undefined) { + browsingContext ||= this._linkedBrowser.browsingContext; + // Update dpr first, and then UI zoom. + this.updateDPPXOverride(browsingContext); + browsingContext.fullZoom = this._zoom; } _updateModalDialogs() { @@ -584,7 +595,7 @@ class PageTarget { const toolbarTop = stackRect.y; this._window.resizeBy(width - this._window.innerWidth, height + toolbarTop - this._window.innerHeight); - await this._channel.connect('').send('awaitViewportDimensions', { width, height }); + await this._channel.connect('').send('awaitViewportDimensions', { width: width / this._zoom, height: height / this._zoom }); } else { this._linkedBrowser.style.removeProperty('width'); this._linkedBrowser.style.removeProperty('height'); @@ -596,8 +607,8 @@ class PageTarget { const actualSize = this._linkedBrowser.getBoundingClientRect(); await this._channel.connect('').send('awaitViewportDimensions', { - width: actualSize.width, - height: actualSize.height, + width: actualSize.width / this._zoom, + height: actualSize.height / this._zoom, }); } } @@ -635,7 +646,8 @@ class PageTarget { } updateForcedColorsOverride(browsingContext = undefined) { - (browsingContext || this._linkedBrowser.browsingContext).forcedColorsOverride = (this.forcedColors !== 'no-override' ? this.forcedColors : this._browserContext.forcedColors) || 'no-override'; + const isActive = this.forcedColors === 'active' || this._browserContext.forcedColors === 'active'; + (browsingContext || this._linkedBrowser.browsingContext).forcedColorsOverride = isActive ? 'active' : 'none'; } async setInterceptFileChooserDialog(enabled) { @@ -649,6 +661,14 @@ class PageTarget { await this.updateViewportSize(); } + async setZoom(zoom) { + // This is default range from the ZoomManager. + if (zoom < 0.3 || zoom > 5) + throw new Error('Invalid zoom value, must be between 0.3 and 5'); + this._zoom = zoom; + await this.updateZoom(); + } + close(runBeforeUnload = false) { this._gBrowser.removeTab(this._tab, { skipPermitUnload: !runBeforeUnload, @@ -858,8 +878,8 @@ function fromProtocolReducedMotion(reducedMotion) { function fromProtocolForcedColors(forcedColors) { if (forcedColors === 'active' || forcedColors === 'none') return forcedColors; - if (forcedColors === null) - return undefined; + if (!forcedColors) + return 'none'; throw new Error('Unknown forced colors: ' + forcedColors); } @@ -893,7 +913,7 @@ class BrowserContext { this.forceOffline = false; this.disableCache = false; this.colorScheme = 'none'; - this.forcedColors = 'no-override'; + this.forcedColors = 'none'; this.reducedMotion = 'none'; this.videoRecordingOptions = undefined; this.crossProcessCookie = { diff --git a/browser_patches/firefox/juggler/components/Juggler.js b/browser_patches/firefox/juggler/components/Juggler.js index d919935fb50ac..aa51a8887929f 100644 --- a/browser_patches/firefox/juggler/components/Juggler.js +++ b/browser_patches/firefox/juggler/components/Juggler.js @@ -105,7 +105,10 @@ class Juggler { }; // Force create hidden window here, otherwise its creation later closes the web socket! - Services.appShell.hiddenDOMWindow; + // Since https://phabricator.services.mozilla.com/D219834, hiddenDOMWindow is only available on MacOS. + if (Services.appShell.hasHiddenWindow) { + Services.appShell.hiddenDOMWindow; + } let pipeStopped = false; let browserHandler; diff --git a/browser_patches/firefox/juggler/protocol/PageHandler.js b/browser_patches/firefox/juggler/protocol/PageHandler.js index bab151b392177..e8367070a86fe 100644 --- a/browser_patches/firefox/juggler/protocol/PageHandler.js +++ b/browser_patches/firefox/juggler/protocol/PageHandler.js @@ -240,6 +240,10 @@ class PageHandler { await this._pageTarget.setViewportSize(viewportSize === null ? undefined : viewportSize); } + async ['Page.setZoom']({zoom}) { + await this._pageTarget.setZoom(zoom); + } + async ['Runtime.evaluate'](options) { return await this._contentPage.send('evaluate', options); } diff --git a/browser_patches/firefox/juggler/protocol/Protocol.js b/browser_patches/firefox/juggler/protocol/Protocol.js index 2b93186e545ad..6fa3dc855540a 100644 --- a/browser_patches/firefox/juggler/protocol/Protocol.js +++ b/browser_patches/firefox/juggler/protocol/Protocol.js @@ -794,6 +794,11 @@ const Page = { viewportSize: t.Nullable(pageTypes.Size), }, }, + 'setZoom': { + params: { + zoom: t.Number, + }, + }, 'bringToFront': { params: { }, diff --git a/browser_patches/firefox/juggler/screencast/moz.build b/browser_patches/firefox/juggler/screencast/moz.build index e21b177c3965c..f89c54e037e39 100644 --- a/browser_patches/firefox/juggler/screencast/moz.build +++ b/browser_patches/firefox/juggler/screencast/moz.build @@ -23,8 +23,8 @@ XPCOM_MANIFESTS += [ LOCAL_INCLUDES += [ '/dom/media/systemservices', '/media/libyuv/libyuv/include', + '/third_party/abseil-cpp', '/third_party/libwebrtc', - '/third_party/libwebrtc/third_party/abseil-cpp', ] LOCAL_INCLUDES += [ diff --git a/browser_patches/firefox/juggler/screencast/nsScreencastService.cpp b/browser_patches/firefox/juggler/screencast/nsScreencastService.cpp index 062a8514296fa..7256c8c8ea416 100644 --- a/browser_patches/firefox/juggler/screencast/nsScreencastService.cpp +++ b/browser_patches/firefox/juggler/screencast/nsScreencastService.cpp @@ -343,10 +343,17 @@ nsresult nsScreencastService::StartVideoRecording(nsIScreencastServiceClient* aC return NS_ERROR_FAILURE; gfx::IntMargin margin; - auto bounds = widget->GetScreenBounds().ToUnknownRect(); + // Screen bounds is the widget location on screen. + auto screenBounds = widget->GetScreenBounds().ToUnknownRect(); + // Client bounds is the content location, in terms of parent widget. + // To use it, we need to translate it to screen coordinates first. auto clientBounds = widget->GetClientBounds().ToUnknownRect(); + for (auto parent = widget->GetParent(); parent != nullptr; parent = parent->GetParent()) { + auto pb = parent->GetClientBounds().ToUnknownRect(); + clientBounds.MoveBy(pb.X(), pb.Y()); + } // Crop the image to exclude frame (if any). - margin = bounds - clientBounds; + margin = screenBounds - clientBounds; // Crop the image to exclude controls. margin.top += offsetTop; diff --git a/browser_patches/firefox/patches/bootstrap.diff b/browser_patches/firefox/patches/bootstrap.diff index 5902d600c284a..9fecd89256e77 100644 --- a/browser_patches/firefox/patches/bootstrap.diff +++ b/browser_patches/firefox/patches/bootstrap.diff @@ -106,10 +106,10 @@ index 213a99ed433d5219c2b9a64baad82d14cdbcd432..ee4f6484cdfe80899c28a1d9607494e5 browser/chrome/browser/content/activity-stream/data/content/tippytop/favicons/allegro-pl.ico browser/defaults/settings/main/search-config-icons/96327a73-c433-5eb4-a16d-b090cadfb80b diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index da760e143740a166df14d055cf3ec7b095b93d10..a7579b3eae69f3b706094693d9b0edaec049e83b 100644 +index 90c2e7a69076df56392f6d14aacadada7f413e89..9ed24d7d690eca04ef07e9715444227ecf32a008 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in -@@ -189,6 +189,9 @@ +@@ -196,6 +196,9 @@ @RESPATH@/chrome/remote.manifest #endif @@ -167,10 +167,10 @@ index d49c6fbf1bf83b832795fa674f6b41f223eef812..7ea3540947ff5f61b15f27fbf4b95564 const transportProvider = { setListener(upgradeListener) { diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp -index e1721f31d491aa8a7977eaca3d2f7f8a048546de..b3bc2d575dc3f794cbc08c603e70d34bbe69efed 100644 +index b30dab9ecdee37d7db842acaad30ded30fc326b2..534a89916e34f3d4d960dfcf660c38e2d1000e0c 100644 --- a/docshell/base/BrowsingContext.cpp +++ b/docshell/base/BrowsingContext.cpp -@@ -106,8 +106,15 @@ struct ParamTraits +@@ -106,8 +106,11 @@ struct ParamTraits template <> struct ParamTraits @@ -181,14 +181,10 @@ index e1721f31d491aa8a7977eaca3d2f7f8a048546de..b3bc2d575dc3f794cbc08c603e70d34b +template <> +struct ParamTraits + : public mozilla::dom::WebIDLEnumSerializer {}; -+ -+template <> -+struct ParamTraits -+ : public mozilla::dom::WebIDLEnumSerializer {}; template <> - struct ParamTraits -@@ -2818,6 +2825,40 @@ void BrowsingContext::DidSet(FieldIndex, + struct ParamTraits +@@ -2887,6 +2890,23 @@ void BrowsingContext::DidSet(FieldIndex, PresContextAffectingFieldChanged(); } @@ -208,29 +204,12 @@ index e1721f31d491aa8a7977eaca3d2f7f8a048546de..b3bc2d575dc3f794cbc08c603e70d34b + } + }); +} -+ -+void BrowsingContext::DidSet(FieldIndex, -+ dom::ForcedColorsOverride aOldValue) { -+ MOZ_ASSERT(IsTop()); -+ if (ForcedColorsOverride() == aOldValue) { -+ return; -+ } -+ PreOrderWalk([&](BrowsingContext* aContext) { -+ if (nsIDocShell* shell = aContext->GetDocShell()) { -+ if (nsPresContext* pc = shell->GetPresContext()) { -+ pc->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ } -+ }); -+} + void BrowsingContext::DidSet(FieldIndex, nsString&& aOldValue) { MOZ_ASSERT(IsTop()); diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h -index 61135ab0d7894c500c3c5d80d107e283c01b6830..cc8eb043f1f78214843ec7b335dd9932587d9bbd 100644 +index e0310bbed02a805a247e04bdc88ae142bcbe5637..19fe77791b055f7f907a0ab00b03e100a0aac1e8 100644 --- a/docshell/base/BrowsingContext.h +++ b/docshell/base/BrowsingContext.h @@ -203,10 +203,10 @@ struct EmbedderColorSchemes { @@ -246,33 +225,27 @@ index 61135ab0d7894c500c3c5d80d107e283c01b6830..cc8eb043f1f78214843ec7b335dd9932 FIELD(EmbedderElementType, Maybe) \ FIELD(MessageManagerGroup, nsString) \ FIELD(MaxTouchPointsOverride, uint8_t) \ -@@ -244,6 +244,10 @@ struct EmbedderColorSchemes { +@@ -246,6 +246,8 @@ struct EmbedderColorSchemes { * embedder element. */ \ FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \ FIELD(DisplayMode, dom::DisplayMode) \ + /* playwright addition */ \ + FIELD(PrefersReducedMotionOverride, dom::PrefersReducedMotionOverride) \ -+ /* playwright addition */ \ -+ FIELD(ForcedColorsOverride, dom::ForcedColorsOverride) \ /* The number of entries added to the session history because of this \ * browsing context. */ \ FIELD(HistoryEntryCount, uint32_t) \ -@@ -937,6 +941,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return GetPrefersColorSchemeOverride(); +@@ -947,6 +949,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { + return GetForcedColorsOverride(); } + dom::PrefersReducedMotionOverride PrefersReducedMotionOverride() const { + return GetPrefersReducedMotionOverride(); + } -+ -+ dom::ForcedColorsOverride ForcedColorsOverride() const { -+ return GetForcedColorsOverride(); -+ } + bool IsInBFCache() const; bool AllowJavascript() const { return GetAllowJavascript(); } -@@ -1101,6 +1113,23 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { +@@ -1128,6 +1134,15 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { void WalkPresContexts(Callback&&); void PresContextAffectingFieldChanged(); @@ -284,32 +257,24 @@ index 61135ab0d7894c500c3c5d80d107e283c01b6830..cc8eb043f1f78214843ec7b335dd9932 + void DidSet(FieldIndex, + dom::PrefersReducedMotionOverride aOldValue); + -+ -+ bool CanSet(FieldIndex, -+ dom::ForcedColorsOverride, ContentParent*) { -+ return IsTop(); -+ } -+ -+ void DidSet(FieldIndex, -+ dom::ForcedColorsOverride aOldValue); + void DidSet(FieldIndex, nsString&& aOldValue); bool CanSet(FieldIndex, bool, ContentParent*) { diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp -index f0d8cb25398472d8720fcacc47081d95d3e9887c..a680d4458360c8515712ef0a986415113ae8a4e0 100644 +index e73d56380ff6802103896bd63d2e11c26c8ee3f5..2ce283bcc4e6690a26a6483b6b50b24093797e45 100644 --- a/docshell/base/CanonicalBrowsingContext.cpp +++ b/docshell/base/CanonicalBrowsingContext.cpp -@@ -324,6 +324,8 @@ void CanonicalBrowsingContext::ReplacedBy( - txn.SetHasRestoreData(GetHasRestoreData()); +@@ -323,6 +323,8 @@ void CanonicalBrowsingContext::ReplacedBy( txn.SetShouldDelayMediaFromStart(GetShouldDelayMediaFromStart()); txn.SetForceOffline(GetForceOffline()); + txn.SetTopInnerSizeForRFP(GetTopInnerSizeForRFP()); + txn.SetPrefersReducedMotionOverride(GetPrefersReducedMotionOverride()); + txn.SetForcedColorsOverride(GetForcedColorsOverride()); // Propagate some settings on BrowsingContext replacement so they're not lost // on bfcached navigations. These are important for GeckoView (see bug -@@ -1594,6 +1596,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, +@@ -1608,6 +1610,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, return; } @@ -323,7 +288,7 @@ index f0d8cb25398472d8720fcacc47081d95d3e9887c..a680d4458360c8515712ef0a98641511 } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp -index c15a424a05d23287ee21726a5fb21ff5691e4c2b..fa9989e313bbb7bf049ce1519733c4032e9f9b4b 100644 +index 4851148d889bdfc12a4b9a463c05d3fb9f1f593f..9f4e3fd0cdfc66b49b1650a05f4b296603846d84 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -15,6 +15,12 @@ @@ -385,7 +350,7 @@ index c15a424a05d23287ee21726a5fb21ff5691e4c2b..fa9989e313bbb7bf049ce1519733c403 mAllowAuth(mItemType == typeContent), mAllowKeywordFixup(false), mDisableMetaRefreshWhenInactive(false), -@@ -3046,6 +3063,214 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { +@@ -3019,6 +3036,214 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { return NS_OK; } @@ -600,7 +565,7 @@ index c15a424a05d23287ee21726a5fb21ff5691e4c2b..fa9989e313bbb7bf049ce1519733c403 NS_IMETHODIMP nsDocShell::GetIsNavigating(bool* aOut) { *aOut = mIsNavigating; -@@ -4739,7 +4964,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { +@@ -4695,7 +4920,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { } void nsDocShell::ActivenessMaybeChanged() { @@ -609,7 +574,7 @@ index c15a424a05d23287ee21726a5fb21ff5691e4c2b..fa9989e313bbb7bf049ce1519733c403 if (RefPtr presShell = GetPresShell()) { presShell->ActivenessMaybeChanged(); } -@@ -6688,6 +6913,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, +@@ -6619,6 +6844,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, return false; // no entry to save into } @@ -620,7 +585,7 @@ index c15a424a05d23287ee21726a5fb21ff5691e4c2b..fa9989e313bbb7bf049ce1519733c403 MOZ_ASSERT(!mozilla::SessionHistoryInParent(), "mOSHE cannot be non-null with SHIP"); nsCOMPtr viewer = mOSHE->GetDocumentViewer(); -@@ -8420,6 +8649,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { +@@ -8352,6 +8581,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { true, // aForceNoOpener getter_AddRefs(newBC)); MOZ_ASSERT(!newBC); @@ -633,7 +598,7 @@ index c15a424a05d23287ee21726a5fb21ff5691e4c2b..fa9989e313bbb7bf049ce1519733c403 return rv; } -@@ -9556,6 +9791,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, +@@ -9506,6 +9741,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr); nsCOMPtr req; @@ -650,7 +615,7 @@ index c15a424a05d23287ee21726a5fb21ff5691e4c2b..fa9989e313bbb7bf049ce1519733c403 rv = DoURILoad(aLoadState, aCacheKey, getter_AddRefs(req)); if (NS_SUCCEEDED(rv)) { -@@ -12754,6 +12999,9 @@ class OnLinkClickEvent : public Runnable { +@@ -12708,6 +12953,9 @@ class OnLinkClickEvent : public Runnable { mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, mTriggeringPrincipal); } @@ -660,17 +625,17 @@ index c15a424a05d23287ee21726a5fb21ff5691e4c2b..fa9989e313bbb7bf049ce1519733c403 return NS_OK; } -@@ -12843,6 +13091,8 @@ nsresult nsDocShell::OnLinkClick( - nsCOMPtr ev = - new OnLinkClickEvent(this, aContent, loadState, noOpenerImplied, - aIsTrusted, aTriggeringPrincipal); +@@ -12794,6 +13042,8 @@ nsresult nsDocShell::OnLinkClick( + + nsCOMPtr ev = new OnLinkClickEvent( + this, aContent, loadState, noOpenerImplied, aTriggeringPrincipal); + nsCOMPtr observerService = mozilla::services::GetObserverService(); + observerService->NotifyObservers(ToSupports(aContent), "juggler-link-click", nullptr); return Dispatch(ev.forget()); } diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h -index 0ea84df4dde885fd8e7f7e6045db56a0fa6b2691..b00bc444a5a25e63f98e583959d5f6812caf1815 100644 +index 888741f8490d6f0e885ed0ce73115c16e7bbe821..0958824d57a082fecae6dde1eb568f457c42f443 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -15,6 +15,7 @@ @@ -689,7 +654,7 @@ index 0ea84df4dde885fd8e7f7e6045db56a0fa6b2691..b00bc444a5a25e63f98e583959d5f681 class nsGlobalWindowOuter; class FramingChecker; -@@ -401,6 +403,15 @@ class nsDocShell final : public nsDocLoader, +@@ -402,6 +404,15 @@ class nsDocShell final : public nsDocLoader, void SetWillChangeProcess() { mWillChangeProcess = true; } bool WillChangeProcess() { return mWillChangeProcess; } @@ -705,7 +670,7 @@ index 0ea84df4dde885fd8e7f7e6045db56a0fa6b2691..b00bc444a5a25e63f98e583959d5f681 // Create a content viewer within this nsDocShell for the given // `WindowGlobalChild` actor. nsresult CreateDocumentViewerForActor( -@@ -1004,6 +1015,8 @@ class nsDocShell final : public nsDocLoader, +@@ -1005,6 +1016,8 @@ class nsDocShell final : public nsDocLoader, bool CSSErrorReportingEnabled() const { return mCSSErrorReportingEnabled; } @@ -714,7 +679,7 @@ index 0ea84df4dde885fd8e7f7e6045db56a0fa6b2691..b00bc444a5a25e63f98e583959d5f681 // Handles retrieval of subframe session history for nsDocShell::LoadURI. If a // load is requested in a subframe of the current DocShell, the subframe // loadType may need to reflect the loadType of the parent document, or in -@@ -1291,6 +1304,16 @@ class nsDocShell final : public nsDocLoader, +@@ -1282,6 +1295,16 @@ class nsDocShell final : public nsDocLoader, bool mAllowDNSPrefetch : 1; bool mAllowWindowControl : 1; bool mCSSErrorReportingEnabled : 1; @@ -732,7 +697,7 @@ index 0ea84df4dde885fd8e7f7e6045db56a0fa6b2691..b00bc444a5a25e63f98e583959d5f681 bool mAllowKeywordFixup : 1; bool mDisableMetaRefreshWhenInactive : 1; diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl -index fdc04f16c6f547077ad8c872f9357d85d4513c50..199f8fdb0670265c715f99f5cac1a2b2f22c963d 100644 +index 84e821e33e8164829dfee4f05340784e189b90ee..397742551b98d0d9e6fcf94f55efda5ea628b9ac 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -44,6 +44,7 @@ interface nsIURI; @@ -781,10 +746,10 @@ index fdc04f16c6f547077ad8c872f9357d85d4513c50..199f8fdb0670265c715f99f5cac1a2b2 * This attempts to save any applicable layout history state (like * scroll position) in the nsISHEntry. This is normally done diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp -index 79f3524037e954eb693e2882d91a7632e6e1df41..2b75a1eaff4d166f68ca4a943e10cf9c6ab28bbf 100644 +index 8680bd4e64abc48233b5babb3b4123fea0e76f3b..44ea1267771cd925df74c716cc26d7ab51b2b985 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp -@@ -3783,6 +3783,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { +@@ -3741,6 +3741,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { } void Document::ApplySettingsFromCSP(bool aSpeculative) { @@ -794,7 +759,7 @@ index 79f3524037e954eb693e2882d91a7632e6e1df41..2b75a1eaff4d166f68ca4a943e10cf9c nsresult rv = NS_OK; if (!aSpeculative) { // 1) apply settings from regular CSP -@@ -3840,6 +3843,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { +@@ -3798,6 +3801,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { MOZ_ASSERT(!mScriptGlobalObject, "CSP must be initialized before mScriptGlobalObject is set!"); @@ -806,7 +771,7 @@ index 79f3524037e954eb693e2882d91a7632e6e1df41..2b75a1eaff4d166f68ca4a943e10cf9c // If this is a data document - no need to set CSP. if (mLoadedAsData) { return NS_OK; -@@ -4641,6 +4649,10 @@ bool Document::HasFocus(ErrorResult& rv) const { +@@ -4605,6 +4613,10 @@ bool Document::HasFocus(ErrorResult& rv) const { return false; } @@ -817,7 +782,7 @@ index 79f3524037e954eb693e2882d91a7632e6e1df41..2b75a1eaff4d166f68ca4a943e10cf9c if (!fm->IsInActiveWindow(bc)) { return false; } -@@ -19139,6 +19151,66 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { +@@ -19488,6 +19500,35 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { return PreferenceSheet::PrefsFor(*this).mColorScheme; } @@ -849,57 +814,25 @@ index 79f3524037e954eb693e2882d91a7632e6e1df41..2b75a1eaff4d166f68ca4a943e10cf9c + + return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; +} -+ -+bool Document::ForcedColors() const { -+ auto* docShell = static_cast(GetDocShell()); -+ nsIDocShell::ForcedColorsOverride forcedColors; -+ if (docShell && docShell->GetForcedColorsOverride(&forcedColors) == NS_OK) { -+ switch (forcedColors) { -+ case nsIDocShell::FORCED_COLORS_OVERRIDE_ACTIVE: -+ return true; -+ case nsIDocShell::FORCED_COLORS_OVERRIDE_NONE: -+ return false; -+ case nsIDocShell::FORCED_COLORS_OVERRIDE_NO_OVERRIDE: -+ break; -+ }; -+ } -+ -+ if (auto* bc = GetBrowsingContext()) { -+ switch (bc->Top()->ForcedColorsOverride()) { -+ case dom::ForcedColorsOverride::Active: -+ return true; -+ case dom::ForcedColorsOverride::None: -+ return false; -+ case dom::ForcedColorsOverride::No_override: -+ break; -+ } -+ } -+ -+ if (mIsBeingUsedAsImage) { -+ return false; -+ } -+ return !PreferenceSheet::PrefsFor(*this).mUseDocumentColors; -+} + bool Document::HasRecentlyStartedForegroundLoads() { if (!sLoadingForegroundTopLevelContentDocument) { return false; diff --git a/dom/base/Document.h b/dom/base/Document.h -index 7a8d8f2a716fc613c4095eaf1a18017887b9b924..e030e6b7ad63ad7c95227ed8f54e946190a638d8 100644 +index ee5800c51cacc7ac3517c03274ed4e0a35e57f9f..91a8ea64eb40dc0e642e8ab515b78c93e11d7d5a 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h -@@ -4077,6 +4077,9 @@ class Document : public nsINode, +@@ -4123,6 +4123,8 @@ class Document : public nsINode, // color-scheme meta tag. ColorScheme DefaultColorScheme() const; + bool PrefersReducedMotion() const; -+ bool ForcedColors() const; + static bool HasRecentlyStartedForegroundLoads(); static bool AutomaticStorageAccessPermissionCanBeGranted( diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp -index e26e0968c11905a39bfcfeea60b4989126780084..376165771df0e215d9e1c78ae5d3669e525bcf31 100644 +index 0f159ad09a2a4b8962307b9f20abf30323377a36..e0cbb3f1f8af42825696d7152eb9993ab3802f90 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -344,14 +344,18 @@ void Navigator::GetAppName(nsAString& aAppName) const { @@ -938,7 +871,7 @@ index e26e0968c11905a39bfcfeea60b4989126780084..376165771df0e215d9e1c78ae5d3669e // The returned value is cached by the binding code. The window listens to the // accept languages change and will clear the cache when needed. It has to -@@ -2307,7 +2317,8 @@ bool Navigator::Webdriver() { +@@ -2298,7 +2308,8 @@ bool Navigator::Webdriver() { } #endif @@ -962,10 +895,10 @@ index 6abf6cef230c97815f17f6b7abf9f1b1de274a6f..46ead1f32e0d710b5b32e61dff72a4f7 dom::MediaCapabilities* MediaCapabilities(); dom::MediaSession* MediaSession(); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp -index 8518005d2938d35da7681c1b4230cacbe8fbaf03..e501e7e3351b6f5bdd07020dea658b9f8508b126 100644 +index 13ba7fa81c67f41e419a13c74f9c382193e0eb27..f438d58b594e1434d090eecc89accc66b9f62fcd 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp -@@ -8809,7 +8809,8 @@ nsresult nsContentUtils::SendMouseEvent( +@@ -8773,7 +8773,8 @@ nsresult nsContentUtils::SendMouseEvent( bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, PreventDefaultResult* aPreventDefault, bool aIsDOMEventSynthesized, @@ -975,7 +908,7 @@ index 8518005d2938d35da7681c1b4230cacbe8fbaf03..e501e7e3351b6f5bdd07020dea658b9f nsPoint offset; nsCOMPtr widget = GetWidget(aPresShell, &offset); if (!widget) return NS_ERROR_FAILURE; -@@ -8817,6 +8818,7 @@ nsresult nsContentUtils::SendMouseEvent( +@@ -8781,6 +8782,7 @@ nsresult nsContentUtils::SendMouseEvent( EventMessage msg; Maybe exitFrom; bool contextMenuKey = false; @@ -983,7 +916,7 @@ index 8518005d2938d35da7681c1b4230cacbe8fbaf03..e501e7e3351b6f5bdd07020dea658b9f if (aType.EqualsLiteral("mousedown")) { msg = eMouseDown; } else if (aType.EqualsLiteral("mouseup")) { -@@ -8841,6 +8843,12 @@ nsresult nsContentUtils::SendMouseEvent( +@@ -8806,6 +8808,12 @@ nsresult nsContentUtils::SendMouseEvent( msg = eMouseHitTest; } else if (aType.EqualsLiteral("MozMouseExploreByTouch")) { msg = eMouseExploreByTouch; @@ -996,7 +929,7 @@ index 8518005d2938d35da7681c1b4230cacbe8fbaf03..e501e7e3351b6f5bdd07020dea658b9f } else { return NS_ERROR_FAILURE; } -@@ -8851,7 +8859,14 @@ nsresult nsContentUtils::SendMouseEvent( +@@ -8816,7 +8824,14 @@ nsresult nsContentUtils::SendMouseEvent( Maybe pointerEvent; Maybe mouseEvent; @@ -1012,7 +945,7 @@ index 8518005d2938d35da7681c1b4230cacbe8fbaf03..e501e7e3351b6f5bdd07020dea658b9f MOZ_ASSERT(!aIsWidgetEventSynthesized, "The event shouldn't be dispatched as a synthesized event"); if (MOZ_UNLIKELY(aIsWidgetEventSynthesized)) { -@@ -8870,8 +8885,11 @@ nsresult nsContentUtils::SendMouseEvent( +@@ -8835,8 +8850,11 @@ nsresult nsContentUtils::SendMouseEvent( contextMenuKey ? WidgetMouseEvent::eContextMenuKey : WidgetMouseEvent::eNormal); } @@ -1024,7 +957,7 @@ index 8518005d2938d35da7681c1b4230cacbe8fbaf03..e501e7e3351b6f5bdd07020dea658b9f mouseOrPointerEvent.pointerId = aIdentifier; mouseOrPointerEvent.mModifiers = GetWidgetModifiers(aModifiers); mouseOrPointerEvent.mButton = aButton; -@@ -8884,6 +8902,8 @@ nsresult nsContentUtils::SendMouseEvent( +@@ -8849,6 +8867,8 @@ nsresult nsContentUtils::SendMouseEvent( mouseOrPointerEvent.mClickCount = aClickCount; mouseOrPointerEvent.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; mouseOrPointerEvent.mExitFrom = exitFrom; @@ -1034,10 +967,10 @@ index 8518005d2938d35da7681c1b4230cacbe8fbaf03..e501e7e3351b6f5bdd07020dea658b9f nsPresContext* presContext = aPresShell->GetPresContext(); if (!presContext) return NS_ERROR_FAILURE; diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h -index b4b2244ddfbe43efa055788297a103c49989d921..2d22cdf8b25d9ce0e0daabb09f315d61a214a2be 100644 +index a1efe3efc7f48f9ff8e2b1a1a50e5dd7bf81f263..caf55fa9dae74ce4ce9ad0369c8cfc8eea061778 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h -@@ -3047,7 +3047,8 @@ class nsContentUtils { +@@ -3033,7 +3033,8 @@ class nsContentUtils { int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, mozilla::PreventDefaultResult* aPreventDefault, @@ -1048,10 +981,10 @@ index b4b2244ddfbe43efa055788297a103c49989d921..2d22cdf8b25d9ce0e0daabb09f315d61 static void FirePageShowEventForFrameLoaderSwap( nsIDocShellTreeItem* aItem, diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp -index c77bf80d5e1fc6db342ab47e85b7950f8a15a2d8..2f61c71cdb82b73c1de1a357315d9243a0b8c639 100644 +index aae46b9bd2e7756fc025c0597db221c579cac679..5e8ae13a9d1747312cd7df9d80cbb1677530465c 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp -@@ -685,6 +685,26 @@ nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) { +@@ -686,6 +686,26 @@ nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) { return NS_ERROR_FAILURE; } @@ -1078,7 +1011,7 @@ index c77bf80d5e1fc6db342ab47e85b7950f8a15a2d8..2f61c71cdb82b73c1de1a357315d9243 NS_IMETHODIMP nsDOMWindowUtils::SendMouseEvent( const nsAString& aType, float aX, float aY, int32_t aButton, -@@ -699,7 +719,7 @@ nsDOMWindowUtils::SendMouseEvent( +@@ -700,7 +720,7 @@ nsDOMWindowUtils::SendMouseEvent( aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, false, aPreventDefault, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, @@ -1087,7 +1020,7 @@ index c77bf80d5e1fc6db342ab47e85b7950f8a15a2d8..2f61c71cdb82b73c1de1a357315d9243 } NS_IMETHODIMP -@@ -717,7 +737,7 @@ nsDOMWindowUtils::SendMouseEventToWindow( +@@ -718,7 +738,7 @@ nsDOMWindowUtils::SendMouseEventToWindow( aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, true, nullptr, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, @@ -1096,7 +1029,7 @@ index c77bf80d5e1fc6db342ab47e85b7950f8a15a2d8..2f61c71cdb82b73c1de1a357315d9243 } NS_IMETHODIMP -@@ -726,13 +746,13 @@ nsDOMWindowUtils::SendMouseEventCommon( +@@ -727,13 +747,13 @@ nsDOMWindowUtils::SendMouseEventCommon( int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aPointerId, bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, @@ -1126,10 +1059,10 @@ index 47ff326b202266b1d7d6af8bdfb72776df8a6a93..b8e084b0c788c46345b1455b8257f171 MOZ_CAN_RUN_SCRIPT nsresult SendTouchEventCommon( diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp -index cbd5cb8e4525454cac0470a14bdc63d45bf53b9a..a73297f3faafe5895453f0a6996aa30a77a97267 100644 +index 54cf5e2647a8fa097481e972e0ab67928b2abc8b..37ff283278cebc0e058b0345a157036283847de8 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp -@@ -1697,6 +1697,10 @@ Maybe nsFocusManager::SetFocusInner(Element* aNewContent, +@@ -1712,6 +1712,10 @@ Maybe nsFocusManager::SetFocusInner(Element* aNewContent, (GetActiveBrowsingContext() == newRootBrowsingContext); } @@ -1140,7 +1073,7 @@ index cbd5cb8e4525454cac0470a14bdc63d45bf53b9a..a73297f3faafe5895453f0a6996aa30a // Exit fullscreen if a website focuses another window if (StaticPrefs::full_screen_api_exit_on_windowRaise() && !isElementInActiveWindow && (aFlags & FLAG_RAISE)) { -@@ -2282,6 +2286,7 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, +@@ -2297,6 +2301,7 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, bool aIsLeavingDocument, bool aAdjustWidget, bool aRemainActive, Element* aElementToFocus, uint64_t aActionId) { @@ -1148,7 +1081,7 @@ index cbd5cb8e4525454cac0470a14bdc63d45bf53b9a..a73297f3faafe5895453f0a6996aa30a LOGFOCUS(("<>", aActionId)); // hold a reference to the focused content, which may be null -@@ -2328,6 +2333,11 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, +@@ -2343,6 +2348,11 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, return true; } @@ -1160,7 +1093,7 @@ index cbd5cb8e4525454cac0470a14bdc63d45bf53b9a..a73297f3faafe5895453f0a6996aa30a // Keep a ref to presShell since dispatching the DOM event may cause // the document to be destroyed. RefPtr presShell = docShell->GetPresShell(); -@@ -3005,7 +3015,9 @@ void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow, +@@ -3020,7 +3030,9 @@ void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow, } } @@ -1172,7 +1105,7 @@ index cbd5cb8e4525454cac0470a14bdc63d45bf53b9a..a73297f3faafe5895453f0a6996aa30a // care of lowering the present active window. This happens in // a separate runnable to avoid touching multiple windows in diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp -index f2aa07e2c1e6df28e165b1868ad9717248360972..2b1b406c4fdf6d0716b9c29c3e640de210eae749 100644 +index d8ba9e36c98197a7dd7e1b0781f2477c451fc5fd..f3b5b0417ed9433678c7379d304de263c7bc1f80 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -2516,10 +2516,16 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, @@ -1217,7 +1150,7 @@ index f2aa07e2c1e6df28e165b1868ad9717248360972..2b1b406c4fdf6d0716b9c29c3e640de2 void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h -index e2a2b560b565e6eb3cd5b4e77eb30051afe7a418..81eaca3fb0acfe90bf07acb4115a0db0786c6998 100644 +index d4347e7a508742986f634e97394a9e3dd435d170..5088520537c8c5c6cc79c1dffd91a68de09f27eb 100644 --- a/dom/base/nsGlobalWindowOuter.h +++ b/dom/base/nsGlobalWindowOuter.h @@ -317,6 +317,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, @@ -1229,10 +1162,10 @@ index e2a2b560b565e6eb3cd5b4e77eb30051afe7a418..81eaca3fb0acfe90bf07acb4115a0db0 // Outer windows only. virtual void EnsureSizeAndPositionUpToDate() override; diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp -index 091d04dd79da3acc33aa22405ddb984ba486dfe2..40bb124fd735c2d214221c1a5fac442e26f7564e 100644 +index 855ba87b5b6db67d7dd207cb54001190c494c61a..f96eb49056dafcbd0ca244dac6d1d4a38e7819ce 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp -@@ -1402,6 +1402,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, +@@ -1438,6 +1438,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); } @@ -1295,10 +1228,10 @@ index 091d04dd79da3acc33aa22405ddb984ba486dfe2..40bb124fd735c2d214221c1a5fac442e DOMQuad& aQuad, const GeometryNode& aFrom, const ConvertCoordinateOptions& aOptions, CallerType aCallerType, diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h -index 3bc7ff8a3d9e7f3148f51da13f34ea1b3ca2ba77..dcb47740ca93ab237e4f55d4225f77283f5f404b 100644 +index e1fb6c2aeb67ab600b668b342bee0c716427d116..55e573dce8ad4d34542f89b9179a1da14f45d1bc 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h -@@ -2317,6 +2317,10 @@ class nsINode : public mozilla::dom::EventTarget { +@@ -2356,6 +2356,10 @@ class nsINode : public mozilla::dom::EventTarget { nsTArray>& aResult, ErrorResult& aRv); @@ -1310,10 +1243,10 @@ index 3bc7ff8a3d9e7f3148f51da13f34ea1b3ca2ba77..dcb47740ca93ab237e4f55d4225f7728 DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, const ConvertCoordinateOptions& aOptions, CallerType aCallerType, diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp -index 48df3ae2d30b975269d06e6354b143abd3e5fcd8..87c8d237355668b0ff324f49be879219b1761083 100644 +index bf7eb34da03c0958de688deecb53b407d430f645..a2ec3b1b7e86f72bee38d890c0834abfe4be8637 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp -@@ -149,6 +149,11 @@ bool nsJSUtils::GetScopeChainForElement( +@@ -149,6 +149,11 @@ bool nsJSUtils::GetEnvironmentChainForElement(JSContext* aCx, Element* aElement, return true; } @@ -1326,23 +1259,23 @@ index 48df3ae2d30b975269d06e6354b143abd3e5fcd8..87c8d237355668b0ff324f49be879219 void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); } diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h -index 8b4c1492c64884d83eb1553bc40b921e0da601b7..ee66eaa21d8e8c208204ef73fca5b3d78abefb24 100644 +index f32e21752d5013bf143eb45391ab9218debab08e..83763d2354dade2f8d2b7930ba18ae91c55133ad 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h -@@ -71,6 +71,7 @@ class nsJSUtils { - JSContext* aCx, mozilla::dom::Element* aElement, - JS::MutableHandleVector aScopeChain); +@@ -75,6 +75,7 @@ class nsJSUtils { + mozilla::dom::Element* aElement, + JS::EnvironmentChain& aEnvChain); + static bool SetTimeZoneOverride(const char* timezoneId); static void ResetTimeZone(); static bool DumpEnabled(); diff --git a/dom/chrome-webidl/BrowsingContext.webidl b/dom/chrome-webidl/BrowsingContext.webidl -index 864890f6a23b21a2a59687e4e2873b6837c05fbb..a34005c323d4b8e35b5bdb2b6eec2a268f8adc4b 100644 +index 28e8d8cb9c61ff8362b2d191d47c3630d2cb0b34..0058e60aaab21f8003bbe1bf3f271c63ed78f29a 100644 --- a/dom/chrome-webidl/BrowsingContext.webidl +++ b/dom/chrome-webidl/BrowsingContext.webidl -@@ -53,6 +53,24 @@ enum PrefersColorSchemeOverride { - "dark", +@@ -61,6 +61,15 @@ enum ForcedColorsOverride { + "active", }; +/** @@ -1353,37 +1286,25 @@ index 864890f6a23b21a2a59687e4e2873b6837c05fbb..a34005c323d4b8e35b5bdb2b6eec2a26 + "reduce", + "no-preference", +}; -+ -+/** -+ * CSS forced-colors values. -+ */ -+enum ForcedColorsOverride { -+ "none", -+ "active", -+ "no-override", /* This clears the override. */ -+}; + /** * Allowed overrides of platform/pref default behaviour for touch events. */ -@@ -209,6 +227,12 @@ interface BrowsingContext { - // Color-scheme simulation, for DevTools. - [SetterThrows] attribute PrefersColorSchemeOverride prefersColorSchemeOverride; +@@ -220,6 +229,9 @@ interface BrowsingContext { + // Forced-colors simulation, for DevTools + [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride; + // Reduced-Motion simulation, for DevTools. + [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride; -+ -+ // Forced-Colors simulation, for DevTools. -+ [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride; + /** * A unique identifier for the browser element that is hosting this * BrowsingContext tree. Every BrowsingContext in the element's tree will diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp -index 21717aba5547b973e439ae9ba525f358d044d3f8..274cdebc2e0a2eb9f8b7743d24921204a417f76d 100644 +index 6a624e4c0f5fb8ffff06419a29f6e6acc6108773..370625634f7846d0545ec7ee964d7fa1a15b3ac0 100644 --- a/dom/geolocation/Geolocation.cpp +++ b/dom/geolocation/Geolocation.cpp -@@ -24,6 +24,7 @@ +@@ -29,6 +29,7 @@ #include "nsComponentManagerUtils.h" #include "nsContentPermissionHelper.h" #include "nsContentUtils.h" @@ -1391,7 +1312,7 @@ index 21717aba5547b973e439ae9ba525f358d044d3f8..274cdebc2e0a2eb9f8b7743d24921204 #include "nsGlobalWindowInner.h" #include "mozilla/dom/Document.h" #include "nsINamed.h" -@@ -264,10 +265,8 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { +@@ -429,10 +430,8 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { return NS_OK; } @@ -1404,7 +1325,7 @@ index 21717aba5547b973e439ae9ba525f358d044d3f8..274cdebc2e0a2eb9f8b7743d24921204 CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition(); if (lastPosition.position) { EpochTimeStamp cachedPositionTime_ms; -@@ -475,8 +474,7 @@ void nsGeolocationRequest::Shutdown() { +@@ -640,8 +639,7 @@ void nsGeolocationRequest::Shutdown() { // If there are no other high accuracy requests, the geolocation service will // notify the provider to switch to the default accuracy. if (mOptions && mOptions->mEnableHighAccuracy) { @@ -1414,7 +1335,7 @@ index 21717aba5547b973e439ae9ba525f358d044d3f8..274cdebc2e0a2eb9f8b7743d24921204 if (gs) { gs->UpdateAccuracy(); } -@@ -785,8 +783,14 @@ void nsGeolocationService::StopDevice() { +@@ -958,8 +956,14 @@ void nsGeolocationService::StopDevice() { StaticRefPtr nsGeolocationService::sService; already_AddRefed @@ -1430,7 +1351,7 @@ index 21717aba5547b973e439ae9ba525f358d044d3f8..274cdebc2e0a2eb9f8b7743d24921204 if (nsGeolocationService::sService) { result = nsGeolocationService::sService; -@@ -878,7 +882,9 @@ nsresult Geolocation::Init(nsPIDOMWindowInner* aContentDom) { +@@ -1051,7 +1055,9 @@ nsresult Geolocation::Init(nsPIDOMWindowInner* aContentDom) { // If no aContentDom was passed into us, we are being used // by chrome/c++ and have no mOwner, no mPrincipal, and no need // to prompt. @@ -1442,7 +1363,7 @@ index 21717aba5547b973e439ae9ba525f358d044d3f8..274cdebc2e0a2eb9f8b7743d24921204 mService->AddLocator(this); } diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h -index 7e1af00d05fbafa2d828e2c7e4dcc5c82d115f5b..e85af9718d064e4d2865bc944e9d4ba1efb9a5d7 100644 +index 992de29b5d2d09c19e55ebb2502215ec9d05a171..cdc20567b693283b0fd5a5923f7ea54210bd1712 100644 --- a/dom/geolocation/Geolocation.h +++ b/dom/geolocation/Geolocation.h @@ -31,6 +31,7 @@ @@ -1453,7 +1374,7 @@ index 7e1af00d05fbafa2d828e2c7e4dcc5c82d115f5b..e85af9718d064e4d2865bc944e9d4ba1 class nsGeolocationService; class nsGeolocationRequest; -@@ -48,13 +49,14 @@ struct CachedPositionAndAccuracy { +@@ -51,13 +52,14 @@ struct CachedPositionAndAccuracy { bool isHighAccuracy; }; @@ -1469,9 +1390,9 @@ index 7e1af00d05fbafa2d828e2c7e4dcc5c82d115f5b..e85af9718d064e4d2865bc944e9d4ba1 static mozilla::StaticRefPtr sService; NS_DECL_THREADSAFE_ISUPPORTS -@@ -179,6 +181,8 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache { - // null. - static already_AddRefed NonWindowSingleton(); +@@ -189,6 +191,8 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache { + BrowsingContext* aBrowsingContext, + geolocation::ParentRequestResolver&& aResolver); + nsGeolocationService* GetGeolocationService() { return mService; }; + @@ -1479,10 +1400,10 @@ index 7e1af00d05fbafa2d828e2c7e4dcc5c82d115f5b..e85af9718d064e4d2865bc944e9d4ba1 ~Geolocation(); diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp -index d40c2a230c8c86f585935061d05e20b405c906fe..29547e7a0d75fdc8b8b30344db32287424e65fba 100644 +index 4b6686880b9fca9bb7c08e850918a4c0f15dac88..825a006b05947ede8ffdfefa4cd12dd5663fb98f 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp -@@ -60,6 +60,7 @@ +@@ -62,6 +62,7 @@ #include "mozilla/dom/Document.h" #include "mozilla/dom/HTMLDataListElement.h" #include "mozilla/dom/HTMLOptionElement.h" @@ -1490,7 +1411,7 @@ index d40c2a230c8c86f585935061d05e20b405c906fe..29547e7a0d75fdc8b8b30344db322874 #include "nsIFrame.h" #include "nsRangeFrame.h" #include "nsError.h" -@@ -783,6 +784,13 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { +@@ -789,6 +790,13 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { return NS_ERROR_FAILURE; } @@ -1505,7 +1426,7 @@ index d40c2a230c8c86f585935061d05e20b405c906fe..29547e7a0d75fdc8b8b30344db322874 return NS_OK; } diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl -index 89202fa1ff22593e7cb5e20fc40b3b3b8e114449..61ed40c8454c6e85876cbc7c240496cc96f77239 100644 +index b4d065ff3197404f92e099afea9a0dcb4ff79bf1..59448d3c4f1054a8a1c8cb415f36fdeb2983040d 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -374,6 +374,26 @@ interface nsIDOMWindowUtils : nsISupports { @@ -1536,10 +1457,10 @@ index 89202fa1ff22593e7cb5e20fc40b3b3b8e114449..61ed40c8454c6e85876cbc7c240496cc * touchstart, touchend, touchmove, and touchcancel * diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp -index 0335a887fe157210f9eef58bf63be879f7d5de2b..dfbb8dae406f9d9276a2719f515ac5a51f8a671d 100644 +index 067e8551685497a8d7681296bbb7d7eae1d7587b..5667fbbfff99b77992eac181304093d8afbff367 100644 --- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp -@@ -1656,6 +1656,21 @@ void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, +@@ -1674,6 +1674,21 @@ void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, if (postLayerization) { postLayerization->Register(); } @@ -1576,10 +1497,10 @@ index 5aa445d2e0a6169e57c44569974d557b3baf7064..671f71979b407f0ca17c66f13805e851 } diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -index d4b40fda96ea759eb92e1351e1046a9e0b85689b..b2123a3be05b2622a5e07d5ee32752d0feaaa57f 100644 +index c43a1b3b245101c974742c5e50f54857e538bbfb..c07a568da3342cbf2af07471fa6959cb242b9a4e 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -@@ -137,9 +137,10 @@ int32_t ScreenDeviceInfoImpl::GetOrientation(const char* aDeviceUniqueIdUTF8, +@@ -52,9 +52,10 @@ namespace webrtc { DesktopCaptureImpl* DesktopCaptureImpl::Create(const int32_t aModuleId, const char* aUniqueId, @@ -1591,30 +1512,20 @@ index d4b40fda96ea759eb92e1351e1046a9e0b85689b..b2123a3be05b2622a5e07d5ee32752d0 + aType, aCaptureCursor); } - int32_t WindowDeviceInfoImpl::Init() { -@@ -412,7 +413,7 @@ static bool UsePipewire() { + static DesktopCaptureOptions CreateDesktopCaptureOptions() { +@@ -155,8 +156,10 @@ static std::unique_ptr CreateTabCapturer( static std::unique_ptr CreateDesktopCapturerAndThread( CaptureDeviceType aDeviceType, DesktopCapturer::SourceId aSourceId, - nsIThread** aOutThread) { + nsIThread** aOutThread, bool aCaptureCursor) { DesktopCaptureOptions options = CreateDesktopCaptureOptions(); - std::unique_ptr capturer; - -@@ -462,8 +463,10 @@ static std::unique_ptr CreateDesktopCapturerAndThread( - - capturer->SelectSource(aSourceId); - -- capturer = std::make_unique(std::move(capturer), -- options); -+ if (aCaptureCursor) { -+ capturer = std::make_unique( -+ std::move(capturer), options); -+ } - } else if (aDeviceType == CaptureDeviceType::Browser) { - // XXX We don't capture cursors, so avoid the extra indirection layer. We - // could also pass null for the pMouseCursorMonitor. -@@ -480,7 +483,8 @@ static std::unique_ptr CreateDesktopCapturerAndThread( ++ if (aCaptureCursor) ++ options.set_prefer_cursor_embedded(aCaptureCursor); + auto ensureThread = [&]() { + if (*aOutThread) { + return *aOutThread; +@@ -253,7 +256,8 @@ static std::unique_ptr CreateDesktopCapturerAndThread( } DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, @@ -1624,7 +1535,7 @@ index d4b40fda96ea759eb92e1351e1046a9e0b85689b..b2123a3be05b2622a5e07d5ee32752d0 : mModuleId(aId), mTrackingId(mozilla::TrackingId(CaptureEngineToTrackingSourceStr([&] { switch (aType) { -@@ -497,6 +501,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, +@@ -270,6 +274,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, aId)), mDeviceUniqueId(aUniqueId), mDeviceType(aType), @@ -1632,7 +1543,7 @@ index d4b40fda96ea759eb92e1351e1046a9e0b85689b..b2123a3be05b2622a5e07d5ee32752d0 mControlThread(mozilla::GetCurrentSerialEventTarget()), mNextFrameMinimumTime(Timestamp::Zero()), mCallbacks("DesktopCaptureImpl::mCallbacks") {} -@@ -521,6 +526,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( +@@ -294,6 +299,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( } } @@ -1652,7 +1563,7 @@ index d4b40fda96ea759eb92e1351e1046a9e0b85689b..b2123a3be05b2622a5e07d5ee32752d0 int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { { auto callbacks = mCallbacks.Lock(); -@@ -553,7 +571,7 @@ int32_t DesktopCaptureImpl::StartCapture( +@@ -333,7 +351,7 @@ int32_t DesktopCaptureImpl::StartCapture( DesktopCapturer::SourceId sourceId = std::stoi(mDeviceUniqueId); std::unique_ptr capturer = CreateDesktopCapturerAndThread( @@ -1661,7 +1572,7 @@ index d4b40fda96ea759eb92e1351e1046a9e0b85689b..b2123a3be05b2622a5e07d5ee32752d0 MOZ_ASSERT(!capturer == !mCaptureThread); if (!capturer) { -@@ -663,6 +681,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result aResult, +@@ -441,6 +459,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result aResult, frameInfo.height = aFrame->size().height(); frameInfo.videoType = VideoType::kARGB; @@ -1678,18 +1589,18 @@ index d4b40fda96ea759eb92e1351e1046a9e0b85689b..b2123a3be05b2622a5e07d5ee32752d0 frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel; diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h -index 9aebaa39321839eb3beb503fc4ed33e303bb0deb..1dd75f3cdb8078b01c4d43a0ac3d8a6ea3ec47ab 100644 +index a76b7de569db1cb42728a5514fb80e5c46e0344e..3d61ad8d3aa4a7eaf96957dcd680e1e1ee8abdf4 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.h +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h -@@ -25,6 +25,7 @@ +@@ -26,6 +26,7 @@ + #include "api/video/video_sink_interface.h" #include "modules/desktop_capture/desktop_capturer.h" #include "modules/video_capture/video_capture.h" - #include "rtc_base/synchronization/mutex.h" +#include "rtc_base/deprecated/recursive_critical_section.h" - - #include "desktop_device_info.h" - #include "MediaEngineSource.h" -@@ -45,6 +46,33 @@ namespace webrtc { + #include "mozilla/DataMutex.h" + #include "mozilla/Maybe.h" + #include "mozilla/TimeStamp.h" +@@ -42,17 +43,44 @@ namespace webrtc { class VideoCaptureEncodeInterface; @@ -1720,10 +1631,7 @@ index 9aebaa39321839eb3beb503fc4ed33e303bb0deb..1dd75f3cdb8078b01c4d43a0ac3d8a6e + int32_t capture_counter_ = 0; +}; + - // simulate deviceInfo interface for video engine, bridge screen/application and - // real screen/application device info - -@@ -160,13 +188,13 @@ class BrowserDeviceInfoImpl : public VideoCaptureModule::DeviceInfo { + // Reuses the video engine pipeline for screen sharing. // As with video, DesktopCaptureImpl is a proxy for screen sharing // and follows the video pipeline design class DesktopCaptureImpl : public DesktopCapturer::Callback, @@ -1739,7 +1647,7 @@ index 9aebaa39321839eb3beb503fc4ed33e303bb0deb..1dd75f3cdb8078b01c4d43a0ac3d8a6e [[nodiscard]] static std::shared_ptr CreateDeviceInfo(const int32_t aId, -@@ -180,6 +208,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, +@@ -66,6 +94,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, void DeRegisterCaptureDataCallback( rtc::VideoSinkInterface* aCallback) override; int32_t StopCaptureIfAllClientsClose() override; @@ -1748,7 +1656,7 @@ index 9aebaa39321839eb3beb503fc4ed33e303bb0deb..1dd75f3cdb8078b01c4d43a0ac3d8a6e int32_t SetCaptureRotation(VideoRotation aRotation) override; bool SetApplyRotation(bool aEnable) override; -@@ -203,7 +233,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, +@@ -89,7 +119,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, protected: DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, @@ -1758,9 +1666,9 @@ index 9aebaa39321839eb3beb503fc4ed33e303bb0deb..1dd75f3cdb8078b01c4d43a0ac3d8a6e virtual ~DesktopCaptureImpl(); private: -@@ -211,6 +242,9 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - static constexpr uint32_t kMaxDesktopCaptureCpuUsage = 50; +@@ -98,6 +129,9 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, void InitOnThread(std::unique_ptr aCapturer, int aFramerate); + void UpdateOnThread(int aFramerate); void ShutdownOnThread(); + + rtc::RecursiveCriticalSection mApiCs; @@ -1768,7 +1676,7 @@ index 9aebaa39321839eb3beb503fc4ed33e303bb0deb..1dd75f3cdb8078b01c4d43a0ac3d8a6e // DesktopCapturer::Callback interface. void OnCaptureResult(DesktopCapturer::Result aResult, std::unique_ptr aFrame) override; -@@ -218,6 +252,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, +@@ -105,6 +139,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, // Notifies all mCallbacks of OnFrame(). mCaptureThread only. void NotifyOnFrame(const VideoFrame& aFrame); @@ -1822,10 +1730,10 @@ index 3b39538e51840cd9b1685b2efd2ff2e9ec83608a..c7bf4f2d53b58bbacb22b3ebebf6f3fc return aGlobalOrNull; diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp -index ff2e907c0d8fc05c6e39fae612eceed405b62712..40ec25b5588a1628f9d9bd16886bed83dad49b90 100644 +index 8c4364190dadd1a58bfd99e2c0dae1524a4e2c0c..ffadb3b4665a804320724b5a12e09cb29ef31498 100644 --- a/dom/security/nsCSPUtils.cpp +++ b/dom/security/nsCSPUtils.cpp -@@ -22,6 +22,7 @@ +@@ -23,6 +23,7 @@ #include "nsSandboxFlags.h" #include "nsServiceManagerUtils.h" #include "nsWhitespaceTokenizer.h" @@ -1833,7 +1741,7 @@ index ff2e907c0d8fc05c6e39fae612eceed405b62712..40ec25b5588a1628f9d9bd16886bed83 #include "mozilla/Assertions.h" #include "mozilla/Components.h" -@@ -133,6 +134,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, +@@ -134,6 +135,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, return; } @@ -1846,19 +1754,19 @@ index ff2e907c0d8fc05c6e39fae612eceed405b62712..40ec25b5588a1628f9d9bd16886bed83 nsContentUtils::TrimWhitespace( aPolicyStr)); diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl -index 2f71b284ee5f7e11f117c447834b48355784448c..2640bd57123c2b03bf4b06a2419cd020ba95f155 100644 +index aee376e971ae01ac1e512c3920b115bfaf06afa8..1701311534bf77e6cd9bafc0e3a283610476aa8f 100644 --- a/dom/webidl/GeometryUtils.webidl +++ b/dom/webidl/GeometryUtils.webidl -@@ -16,6 +16,8 @@ dictionary BoxQuadOptions { - GeometryNode relativeTo; - [ChromeOnly] +@@ -17,6 +17,8 @@ dictionary GeometryUtilsOptions { boolean createFramesForSuppressedWhitespace = true; + [ChromeOnly] + boolean flush = true; + [ChromeOnly] + boolean recurseWhenNoFrame = false; }; - dictionary ConvertCoordinateOptions { -@@ -27,6 +29,9 @@ interface mixin GeometryUtils { + dictionary BoxQuadOptions : GeometryUtilsOptions { +@@ -35,6 +37,9 @@ interface mixin GeometryUtils { [Throws, Func="nsINode::HasBoxQuadsSupport", NeedsCallerType] sequence getBoxQuads(optional BoxQuadOptions options = {}); @@ -1869,10 +1777,10 @@ index 2f71b284ee5f7e11f117c447834b48355784448c..2640bd57123c2b03bf4b06a2419cd020 * returned quads are further translated relative to the window * origin -- which is not the layout origin. Further translation diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp -index 1ba2051ed316956a5a71f85ed5fa0735d54716e5..c0d6f45ce14040a79cfe134a4f8254434a4c53cc 100644 +index 996b5699166711901ff0d11fe64352b6c9c97d1e..5b08ea6145e6052058a55d6a678fd7539f70baa1 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp -@@ -1007,7 +1007,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { +@@ -1005,7 +1005,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { AssertIsOnMainThread(); nsTArray languages; @@ -1881,7 +1789,7 @@ index 1ba2051ed316956a5a71f85ed5fa0735d54716e5..c0d6f45ce14040a79cfe134a4f825443 RuntimeService* runtime = RuntimeService::GetService(); if (runtime) { -@@ -1194,8 +1194,7 @@ bool RuntimeService::RegisterWorker(WorkerPrivate& aWorkerPrivate) { +@@ -1193,8 +1193,7 @@ bool RuntimeService::RegisterWorker(WorkerPrivate& aWorkerPrivate) { } // The navigator overridden properties should have already been read. @@ -1891,7 +1799,7 @@ index 1ba2051ed316956a5a71f85ed5fa0735d54716e5..c0d6f45ce14040a79cfe134a4f825443 mNavigatorPropertiesLoaded = true; } -@@ -1817,6 +1816,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( +@@ -1815,6 +1814,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( } } @@ -1905,7 +1813,7 @@ index 1ba2051ed316956a5a71f85ed5fa0735d54716e5..c0d6f45ce14040a79cfe134a4f825443 template void RuntimeService::BroadcastAllWorkers(const Func& aFunc) { AssertIsOnMainThread(); -@@ -2342,6 +2348,14 @@ void PropagateStorageAccessPermissionGrantedToWorkers( +@@ -2340,6 +2346,14 @@ void PropagateStorageAccessPermissionGrantedToWorkers( } } @@ -1947,10 +1855,10 @@ index 58894a8361c7ef1dddd481ca5877a209a8b8ff5c..c481d40d79b6397b7f1d571bd9f6ae5c bool IsWorkerGlobal(JSObject* global); diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp -index 2b48cc2980165ce51ded62faef96b93b781ede32..d8dc90983353c2f5cc1db56e327c4533d524cc1d 100644 +index 0076a8463fa9ff05b32edfe21462987610432b5d..9f810c9728b7d7caf9fbeb3e24346c219326637d 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp -@@ -700,6 +700,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { +@@ -736,6 +736,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { } }; @@ -1969,7 +1877,7 @@ index 2b48cc2980165ce51ded62faef96b93b781ede32..d8dc90983353c2f5cc1db56e327c4533 class UpdateLanguagesRunnable final : public WorkerThreadRunnable { nsTArray mLanguages; -@@ -2113,6 +2125,16 @@ void WorkerPrivate::UpdateContextOptions( +@@ -2149,6 +2161,16 @@ void WorkerPrivate::UpdateContextOptions( } } @@ -1986,7 +1894,7 @@ index 2b48cc2980165ce51ded62faef96b93b781ede32..d8dc90983353c2f5cc1db56e327c4533 void WorkerPrivate::UpdateLanguages(const nsTArray& aLanguages) { AssertIsOnParentThread(); -@@ -5740,6 +5762,15 @@ void WorkerPrivate::UpdateContextOptionsInternal( +@@ -5833,6 +5855,15 @@ void WorkerPrivate::UpdateContextOptionsInternal( } } @@ -2003,10 +1911,10 @@ index 2b48cc2980165ce51ded62faef96b93b781ede32..d8dc90983353c2f5cc1db56e327c4533 const nsTArray& aLanguages) { WorkerGlobalScope* globalScope = GlobalScope(); diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h -index da25a495a8930f7b88958553164d86fe2869416f..38f92829438ead78d73d96ee48a3fcab46c337d7 100644 +index c2ade467934d08587d4e3589b310c6302534d699..414814c03180b50d218ad84a0db262fff19f78a7 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h -@@ -432,6 +432,8 @@ class WorkerPrivate final +@@ -443,6 +443,8 @@ class WorkerPrivate final void UpdateContextOptionsInternal(JSContext* aCx, const JS::ContextOptions& aContextOptions); @@ -2015,7 +1923,7 @@ index da25a495a8930f7b88958553164d86fe2869416f..38f92829438ead78d73d96ee48a3fcab void UpdateLanguagesInternal(const nsTArray& aLanguages); void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, -@@ -1069,6 +1071,8 @@ class WorkerPrivate final +@@ -1086,6 +1088,8 @@ class WorkerPrivate final void UpdateContextOptions(const JS::ContextOptions& aContextOptions); @@ -2077,10 +1985,10 @@ index 523e84c8c93f4221701f90f2e8ee146ec8e1adbd..98d5b1176e5378431b859a2dbd4d4e77 inline ClippedTime TimeClip(double time); diff --git a/js/src/debugger/Object.cpp b/js/src/debugger/Object.cpp -index 6ca6c31830066f9677988daca8566e93a8335c26..3f963dbf6127c997810e380802e56b023b5db4c8 100644 +index 880e716c24464c93283410417f8e69d6d233d105..6e046fbd2e643dace5ad7796740253df3ddf2cbe 100644 --- a/js/src/debugger/Object.cpp +++ b/js/src/debugger/Object.cpp -@@ -2468,7 +2468,11 @@ Maybe DebuggerObject::call(JSContext* cx, +@@ -2474,7 +2474,11 @@ Maybe DebuggerObject::call(JSContext* cx, invokeArgs[i].set(args2[i]); } @@ -2093,10 +2001,10 @@ index 6ca6c31830066f9677988daca8566e93a8335c26..3f963dbf6127c997810e380802e56b02 } diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp -index 623a6863a54fb0d653ebe55fd83356f1a8c8be15..1c0ef7b0d3ee2f61de728a68dd704a5d09757b38 100644 +index cf63b124f39223a1a42c322dcc0ad108947d54f5..9e3a7b757cbad57ee6cfe2254d0355f62f7c8662 100644 --- a/js/src/vm/DateTime.cpp +++ b/js/src/vm/DateTime.cpp -@@ -186,6 +186,11 @@ void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) { +@@ -185,6 +185,11 @@ void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) { } } @@ -2108,7 +2016,7 @@ index 623a6863a54fb0d653ebe55fd83356f1a8c8be15..1c0ef7b0d3ee2f61de728a68dd704a5d void js::DateTimeInfo::updateTimeZone() { MOZ_ASSERT(timeZoneStatus_ != TimeZoneStatus::Valid); -@@ -529,10 +534,24 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) { +@@ -528,10 +533,24 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) { js::DateTimeInfo::resetTimeZone(mode); } @@ -2133,7 +2041,7 @@ index 623a6863a54fb0d653ebe55fd83356f1a8c8be15..1c0ef7b0d3ee2f61de728a68dd704a5d #if JS_HAS_INTL_API # if defined(XP_WIN) static bool IsOlsonCompatibleWindowsTimeZoneId(std::string_view tz) { -@@ -750,6 +769,15 @@ static bool ReadTimeZoneLink(std::string_view tz, +@@ -749,6 +768,15 @@ static bool ReadTimeZoneLink(std::string_view tz, void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { #if JS_HAS_INTL_API @@ -2149,7 +2057,7 @@ index 623a6863a54fb0d653ebe55fd83356f1a8c8be15..1c0ef7b0d3ee2f61de728a68dd704a5d // In the future we should not be setting a default ICU time zone at all, // instead all accesses should go through the appropriate DateTimeInfo // instance depending on the resist fingerprinting status. For now we return -@@ -761,7 +789,6 @@ void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { +@@ -760,7 +788,6 @@ void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { if (const char* tzenv = std::getenv("TZ")) { std::string_view tz(tzenv); @@ -2158,7 +2066,7 @@ index 623a6863a54fb0d653ebe55fd83356f1a8c8be15..1c0ef7b0d3ee2f61de728a68dd704a5d # if defined(XP_WIN) diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h -index fd6d7ae078b8f6b3cc46a4a993a1e044a7128c90..4743094e489122dd9ee8ab9a7a175dd7e928859d 100644 +index e3cf82daa3749664aa8ced7e6553b8c6434dfec8..b45b49c4f3bbf12853c4afb12de21d99ac88d77b 100644 --- a/js/src/vm/DateTime.h +++ b/js/src/vm/DateTime.h @@ -65,6 +65,8 @@ enum class ResetTimeZoneMode : bool { @@ -2170,7 +2078,7 @@ index fd6d7ae078b8f6b3cc46a4a993a1e044a7128c90..4743094e489122dd9ee8ab9a7a175dd7 /** * Stores date/time information, particularly concerning the current local * time zone, and implements a small cache for daylight saving time offset -@@ -225,6 +227,7 @@ class DateTimeInfo { +@@ -253,6 +255,7 @@ class DateTimeInfo { private: // The method below should only be called via js::ResetTimeZoneInternal(). friend void js::ResetTimeZoneInternal(ResetTimeZoneMode); @@ -2178,7 +2086,7 @@ index fd6d7ae078b8f6b3cc46a4a993a1e044a7128c90..4743094e489122dd9ee8ab9a7a175dd7 static void resetTimeZone(ResetTimeZoneMode mode) { { -@@ -321,6 +324,8 @@ class DateTimeInfo { +@@ -352,6 +355,8 @@ class DateTimeInfo { JS::UniqueChars locale_; JS::UniqueTwoByteChars standardName_; JS::UniqueTwoByteChars daylightSavingsName_; @@ -2187,7 +2095,7 @@ index fd6d7ae078b8f6b3cc46a4a993a1e044a7128c90..4743094e489122dd9ee8ab9a7a175dd7 #else // Restrict the data-time range to the minimum required time_t range as // specified in POSIX. Most operating systems support 64-bit time_t -@@ -336,6 +341,8 @@ class DateTimeInfo { +@@ -367,6 +372,8 @@ class DateTimeInfo { void internalResetTimeZone(ResetTimeZoneMode mode); @@ -2197,7 +2105,7 @@ index fd6d7ae078b8f6b3cc46a4a993a1e044a7128c90..4743094e489122dd9ee8ab9a7a175dd7 void internalResyncICUDefaultTimeZone(); diff --git a/layout/base/GeometryUtils.cpp b/layout/base/GeometryUtils.cpp -index 0ec6ee3eb37c6493d8a25352fd0e54e1927bceab..885dba71bc5815e5f6f3ec2700c376aa119b30d0 100644 +index 4bfd336ddcbee8004ac538ca7b7d8216d04a61c3..cd22351c4aeacea8afc9828972222aca1b3063bf 100644 --- a/layout/base/GeometryUtils.cpp +++ b/layout/base/GeometryUtils.cpp @@ -23,6 +23,7 @@ @@ -2208,18 +2116,18 @@ index 0ec6ee3eb37c6493d8a25352fd0e54e1927bceab..885dba71bc5815e5f6f3ec2700c376aa using namespace mozilla; using namespace mozilla::dom; -@@ -261,11 +262,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, +@@ -265,10 +266,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, return false; } -+static nsIFrame* GetFrameForNode(nsINode* aNode, -+ bool aCreateFramesForSuppressedWhitespace, ++static nsIFrame* GetFrameForNodeRecursive(nsINode* aNode, ++ const GeometryUtilsOptions& aOptions, + bool aRecurseWhenNoFrame) { -+ nsIFrame* frame = GetFrameForNode(aNode, aCreateFramesForSuppressedWhitespace); ++ nsIFrame* frame = GetFrameForNode(aNode, aOptions); + if (!frame && aRecurseWhenNoFrame && aNode->IsContent()) { + dom::FlattenedChildIterator iter(aNode->AsContent()); + for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = GetFrameForNode(child, aCreateFramesForSuppressedWhitespace, aRecurseWhenNoFrame); ++ frame = GetFrameForNodeRecursive(child, aOptions, aRecurseWhenNoFrame); + if (frame) { + break; + } @@ -2229,28 +2137,29 @@ index 0ec6ee3eb37c6493d8a25352fd0e54e1927bceab..885dba71bc5815e5f6f3ec2700c376aa +} + void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - nsTArray >& aResult, CallerType aCallerType, + nsTArray>& aResult, CallerType aCallerType, ErrorResult& aRv) { - nsIFrame* frame = -- GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace); -+ GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace, aOptions.mRecurseWhenNoFrame); +- nsIFrame* frame = GetFrameForNode(aNode, aOptions); ++ nsIFrame* frame = ++ GetFrameForNodeRecursive(aNode, aOptions, aOptions.mRecurseWhenNoFrame); if (!frame) { // No boxes to return return; -@@ -280,7 +297,7 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, +@@ -281,7 +299,8 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, + // EnsureFrameForTextNode call. We need to get the first frame again // when that happens and re-check it. if (!weakFrame.IsAlive()) { - frame = -- GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace); -+ GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace, aOptions.mRecurseWhenNoFrame); +- frame = GetFrameForNode(aNode, aOptions); ++ frame = ++ GetFrameForNodeRecursive(aNode, aOptions, aOptions.mRecurseWhenNoFrame); if (!frame) { // No boxes to return return; diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp -index 2cc3c5673e246ac38cdaddb457ce36ee4c7356ce..61093cd52fc049ad77d84dd837731071fdace69d 100644 +index c533494e49d59904b839ea770475ec726c4c897e..1da4eeb774dadb4e3463cbeb17d857ccb6ef76ea 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp -@@ -11163,7 +11163,9 @@ bool PresShell::ComputeActiveness() const { +@@ -11278,7 +11278,9 @@ bool PresShell::ComputeActiveness() const { if (!browserChild->IsVisible()) { MOZ_LOG(gLog, LogLevel::Debug, (" > BrowserChild %p is not visible", browserChild)); @@ -2262,10 +2171,10 @@ index 2cc3c5673e246ac38cdaddb457ce36ee4c7356ce..61093cd52fc049ad77d84dd837731071 // If the browser is visible but just due to be preserving layers diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp -index d8995d6d94f5861d8ed839613768eb269b44e362..b946de49a0ecab449a9d1aff24c38f69a431eec0 100644 +index 1fba8697d48f35e20a69ff861f5da9689c6d6769..77d0de76f346c0563d9b74b667c8400e26a98694 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp -@@ -698,6 +698,10 @@ bool nsLayoutUtils::AllowZoomingForDocument( +@@ -708,6 +708,10 @@ bool nsLayoutUtils::AllowZoomingForDocument( !aDocument->GetPresShell()->AsyncPanZoomEnabled()) { return false; } @@ -2276,7 +2185,7 @@ index d8995d6d94f5861d8ed839613768eb269b44e362..b946de49a0ecab449a9d1aff24c38f69 // True if we allow zooming for all documents on this platform, or if we are // in RDM. BrowsingContext* bc = aDocument->GetBrowsingContext(); -@@ -9768,6 +9772,9 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, +@@ -9709,6 +9713,9 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, /* static */ bool nsLayoutUtils::ShouldHandleMetaViewport(const Document* aDocument) { @@ -2287,10 +2196,10 @@ index d8995d6d94f5861d8ed839613768eb269b44e362..b946de49a0ecab449a9d1aff24c38f69 return StaticPrefs::dom_meta_viewport_enabled() || (bc && bc->InRDMPane()); } diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h -index c18d38d8ad2f80bb0d3512d1a9ae965c594bb356..22736c86eb5e3d0a44563c312e34032c157f3abe 100644 +index acb5b24776c8591933d1abcbcc7b254cf2ceb4e4..191ddd1f43bd704294727555c3d5137d69c1460c 100644 --- a/layout/style/GeckoBindings.h +++ b/layout/style/GeckoBindings.h -@@ -595,6 +595,7 @@ float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); +@@ -593,6 +593,7 @@ float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); bool Gecko_MediaFeatures_PrefersReducedTransparency( const mozilla::dom::Document*); @@ -2299,10 +2208,10 @@ index c18d38d8ad2f80bb0d3512d1a9ae965c594bb356..22736c86eb5e3d0a44563c312e34032c const mozilla::dom::Document*); mozilla::StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp -index cc86d1abf6ccfe48530607c41cd675612cbe5582..8cce20c719fee8a0480ae6ea1fd53c6639d0bd7b 100644 +index ca382a3cfba8ce5839890d6e4cb3cf9789287e3b..b1f1b579d7609c6ab93cc0bc52417ea54ab4aeed 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp -@@ -260,11 +260,11 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { +@@ -264,11 +264,7 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { } bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { @@ -2312,28 +2221,24 @@ index cc86d1abf6ccfe48530607c41cd675612cbe5582..8cce20c719fee8a0480ae6ea1fd53c66 - } - return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; + return aDocument->PrefersReducedMotion(); -+} -+ -+bool Gecko_MediaFeatures_ForcedColors(const Document* aDocument) { -+ return aDocument->ForcedColors(); } bool Gecko_MediaFeatures_PrefersReducedTransparency(const Document* aDocument) { diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp -index 21d5a5e1b4193d058c30268ab73c8d595436b381..11b960ec0ff3ea77857cb915d05bbdbb6772bb37 100644 +index 06acdc629c2b6ee0e29c50d8edc5a96d343b1ef2..6c263edf54117fd9cbf4a77abc396f1238730880 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp -@@ -693,7 +693,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) - mHasInjectedCookieForCookieBannerHandling( +@@ -696,7 +696,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) rhs.mHasInjectedCookieForCookieBannerHandling), - mWasSchemelessInput(rhs.mWasSchemelessInput), -- mHttpsUpgradeTelemetry(rhs.mHttpsUpgradeTelemetry) { -+ mHttpsUpgradeTelemetry(rhs.mHttpsUpgradeTelemetry), + mSchemelessInput(rhs.mSchemelessInput), + mHttpsUpgradeTelemetry(rhs.mHttpsUpgradeTelemetry), +- mIsNewWindowTarget(rhs.mIsNewWindowTarget) { ++ mIsNewWindowTarget(rhs.mIsNewWindowTarget), + mJugglerLoadIdentifier(rhs.mJugglerLoadIdentifier) { } LoadInfo::LoadInfo( -@@ -2461,4 +2462,16 @@ LoadInfo::SetHttpsUpgradeTelemetry( +@@ -2515,4 +2516,16 @@ LoadInfo::SetSkipHTTPSUpgrade(bool aSkipHTTPSUpgrade) { return NS_OK; } @@ -2351,26 +2256,23 @@ index 21d5a5e1b4193d058c30268ab73c8d595436b381..11b960ec0ff3ea77857cb915d05bbdbb + } // namespace mozilla::net diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h -index 6ba1d8e11efbbf75f4a44d4977587429ad1371f8..d834f1f5528264f59c4547f00825e0a3b433d9dd 100644 +index c78602f6b46c983aa4d96c5727ebbaf7e2c7d984..e292766a0f34306ea1101be4ecd8848764726bad 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h -@@ -413,9 +413,10 @@ class LoadInfo final : public nsILoadInfo { +@@ -423,6 +423,8 @@ class LoadInfo final : public nsILoadInfo { - bool mHasInjectedCookieForCookieBannerHandling = false; - bool mWasSchemelessInput = false; -- - nsILoadInfo::HTTPSUpgradeTelemetryType mHttpsUpgradeTelemetry = - nsILoadInfo::NOT_INITIALIZED; + bool mIsNewWindowTarget = false; + bool mSkipHTTPSUpgrade = false; + + uint64_t mJugglerLoadIdentifier = 0; }; // This is exposed solely for testing purposes and should not be used outside of diff --git a/netwerk/base/TRRLoadInfo.cpp b/netwerk/base/TRRLoadInfo.cpp -index 9dc2bb0da6871b905abd17d931e555429977c6c2..b71cf6393492346f16417b3ba745a235a483be22 100644 +index 5984a0a196615cca5544de052874cbb163a8233b..3617816a06651ae65c214ebd5f0affedc4d11390 100644 --- a/netwerk/base/TRRLoadInfo.cpp +++ b/netwerk/base/TRRLoadInfo.cpp -@@ -903,5 +903,15 @@ TRRLoadInfo::SetHttpsUpgradeTelemetry( +@@ -936,5 +936,15 @@ TRRLoadInfo::GetFetchDestination(nsACString& aDestination) { return NS_ERROR_NOT_IMPLEMENTED; } @@ -2387,13 +2289,14 @@ index 9dc2bb0da6871b905abd17d931e555429977c6c2..b71cf6393492346f16417b3ba745a235 } // namespace net } // namespace mozilla diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl -index daccd1dc75fb1f6ba88c8f734e10c14cbdbffe8f..9621ca5dc05f12a8d81da787fa479fe03ea99e4c 100644 +index 50dfc8767a99eef5e8748d648995f3cd7cc81a73..32a171eac26376144482bc7d90e8662a0e719f47 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl -@@ -1590,4 +1590,5 @@ interface nsILoadInfo : nsISupports +@@ -1616,4 +1616,6 @@ interface nsILoadInfo : nsISupports + * When true, this load will never be upgraded to HTTPS. */ - [infallible] attribute nsILoadInfo_HTTPSUpgradeTelemetryType httpsUpgradeTelemetry; - + [infallible] attribute boolean skipHTTPSUpgrade; ++ + [infallible] attribute unsigned long long jugglerLoadIdentifier; }; diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl @@ -2409,10 +2312,10 @@ index 7f91d2df6f8bb4020c75c132dc8f6bf26625fa1e..ba6569f4be8fc54ec96ee44d5de45a09 /** * Set the status and reason for the forthcoming synthesized response. diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp -index ef946929c9bbd7903c8e3b32bcb373d5096aed52..a2814c5c891e2877aca9fdb4698385282b8743a9 100644 +index 8b392845d07f50dddf016770836107614b6b9753..b0817d1b660dbb2dd856daf30ec9ec0fcb3d2aeb 100644 --- a/netwerk/ipc/DocumentLoadListener.cpp +++ b/netwerk/ipc/DocumentLoadListener.cpp -@@ -171,6 +171,7 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext, +@@ -172,6 +172,7 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext, loadInfo->SetTextDirectiveUserActivation( aLoadState->GetTextDirectiveUserActivation()); loadInfo->SetIsMetaRefresh(aLoadState->IsMetaRefresh()); @@ -2421,10 +2324,10 @@ index ef946929c9bbd7903c8e3b32bcb373d5096aed52..a2814c5c891e2877aca9fdb469838528 return loadInfo.forget(); } diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp -index e81a4538fd45c13aa60d933de5f4f32ce69fb5f2..d7945f81295c497485a09696f06ce041c1cd8079 100644 +index b7c129dcc21cb5d5478765f6aa06ed047aee6de0..6f3881c002c5f6d3e48865d253515ffd4d24bcf6 100644 --- a/netwerk/protocol/http/InterceptedHttpChannel.cpp +++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp -@@ -727,6 +727,14 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor) +@@ -726,6 +726,14 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor) } // anonymous namespace @@ -2439,7 +2342,7 @@ index e81a4538fd45c13aa60d933de5f4f32ce69fb5f2..d7945f81295c497485a09696f06ce041 NS_IMETHODIMP InterceptedHttpChannel::ResetInterception(bool aBypass) { INTERCEPTED_LOG(("InterceptedHttpChannel::ResetInterception [%p] bypass: %s", -@@ -1140,11 +1148,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { +@@ -1139,11 +1147,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { GetCallback(mProgressSink); } @@ -2459,10 +2362,10 @@ index e81a4538fd45c13aa60d933de5f4f32ce69fb5f2..d7945f81295c497485a09696f06ce041 if (mPump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { mPump->PeekStream(CallTypeSniffers, static_cast(this)); diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp -index 071ed8da4135102b0b1fedce32326bdc0657c3fd..063b516001a674b558046f9191f08352eb671801 100644 +index d05b06c3f9ddba3b40d5969730474eaf0d843cb1..9b2cc35c504e1044ac681c62c107f8feb6c16938 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp -@@ -1391,6 +1391,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( +@@ -1334,6 +1334,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); @@ -2547,10 +2450,10 @@ index 6dfd07d6b676a99993408921de8dea9d561f201d..e3c6794363cd6336effbeac83a179f37 readonly attribute boolean securityCheckDisabled; }; diff --git a/services/settings/Utils.sys.mjs b/services/settings/Utils.sys.mjs -index 73c83e526be1a3a252f995d0718e3975d50bffa7..db5977c54221e19e107a8325a0834302c2e84546 100644 +index 12fef6cde815a9301944c399a58f27a7e4c4d5d7..0f7f06d1002a089547d1b15d7d8ddf264f28b529 100644 --- a/services/settings/Utils.sys.mjs +++ b/services/settings/Utils.sys.mjs -@@ -95,7 +95,7 @@ function _isUndefined(value) { +@@ -97,7 +97,7 @@ const _cdnURLs = {}; export var Utils = { get SERVER_URL() { @@ -2559,7 +2462,7 @@ index 73c83e526be1a3a252f995d0718e3975d50bffa7..db5977c54221e19e107a8325a0834302 ? lazy.gServerURL : AppConstants.REMOTE_SETTINGS_SERVER_URL; }, -@@ -108,6 +108,9 @@ export var Utils = { +@@ -110,6 +110,9 @@ export var Utils = { log, get shouldSkipRemoteActivityDueToTests() { @@ -2569,30 +2472,6 @@ index 73c83e526be1a3a252f995d0718e3975d50bffa7..db5977c54221e19e107a8325a0834302 return ( (lazy.isRunningTests || Cu.isInAutomation) && this.SERVER_URL == "data:,#remote-settings-dummy/v1" -diff --git a/servo/components/style/gecko/media_features.rs b/servo/components/style/gecko/media_features.rs -index df1c5e464b845b6a8bfedadb86d0e7aab7fd3ffc..34451e791bb59f635134de702d9e5f641fe8df79 100644 ---- a/servo/components/style/gecko/media_features.rs -+++ b/servo/components/style/gecko/media_features.rs -@@ -303,10 +303,16 @@ impl ForcedColors { - - /// https://drafts.csswg.org/mediaqueries-5/#forced-colors - fn eval_forced_colors(context: &Context, query_value: Option) -> bool { -- let forced = context.device().forced_colors(); -+ let prefers_forced_colors = -+ unsafe { bindings::Gecko_MediaFeatures_ForcedColors(context.device().document()) }; -+ let query_value = match query_value { -+ Some(v) => v, -+ None => return prefers_forced_colors, -+ }; - match query_value { -- Some(query_value) => query_value == forced, -- None => forced != ForcedColors::None, -+ ForcedColors::Active => prefers_forced_colors, -+ ForcedColors::Requested => prefers_forced_colors, -+ ForcedColors::None => !prefers_forced_colors, - } - } - diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl index 75555352b8a15a50e4a21e34fc8ede4e9246c7cc..72855a404effa42b6c55cd0c2fcb8bdd6c2b3f9f 100644 --- a/toolkit/components/browser/nsIWebBrowserChrome.idl @@ -2608,7 +2487,7 @@ index 75555352b8a15a50e4a21e34fc8ede4e9246c7cc..72855a404effa42b6c55cd0c2fcb8bdd // ignored for Linux. const unsigned long CHROME_SUPPRESS_ANIMATION = 1 << 24; diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -index 00a5381133f8cec0de452c31c7151801a1acc0b9..5d3e3d6f566dc724f257beaeb994cedaa7e71139 100644 +index 8b975a8b11bcf2eabbb7fa51a431ff99ff69a5bc..0eeb5924c43a21b8561dd4b68fa89228ddcbc708 100644 --- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs +++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs @@ -108,6 +108,12 @@ EnterprisePoliciesManager.prototype = { @@ -2625,10 +2504,10 @@ index 00a5381133f8cec0de452c31c7151801a1acc0b9..5d3e3d6f566dc724f257beaeb994ceda if (provider.failed) { diff --git a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -index 6a40d032449e780bfeb77934ba141317b94e7189..1468d38355058b985f18613bd6e3bc84086fae40 100644 +index 77496e700eebbf286e8c5175ea1f77f8576fde1f..3d13e9b316284eaef5d4c82087117020ca8aba71 100644 --- a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp +++ b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp -@@ -553,7 +553,7 @@ void PopulateLanguages() { +@@ -488,7 +488,7 @@ void PopulateLanguages() { // sufficient to only collect this information as the other properties are // just reformats of Navigator::GetAcceptLanguages. nsTArray languages; @@ -2638,10 +2517,10 @@ index 6a40d032449e780bfeb77934ba141317b94e7189..1468d38355058b985f18613bd6e3bc84 for (const auto& language : languages) { diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp -index 3314cb813f6ceb67096eeda0864ad3b16c0616cb..5aac63649e186d624a9905a5d16513f8353f5515 100644 +index 9297e5eacd65658289dda764ad39e182c22d192b..15926f106850637a5bbd27e56834dc5c82791250 100644 --- a/toolkit/components/startup/nsAppStartup.cpp +++ b/toolkit/components/startup/nsAppStartup.cpp -@@ -371,7 +371,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { +@@ -365,7 +365,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { nsCOMPtr windowEnumerator; nsCOMPtr mediator( do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); @@ -2666,10 +2545,10 @@ index 654903fadb709be976b72f36f155e23bc0622152..815b3dc24c9fda6b1db6c4666ac68904 int32_t aMaxSelfProgress, int32_t aCurTotalProgress, diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -index e3f616c4efd5d7e10ed372afa4b5c4d2d93e6a67..abb7772184c9baf23025c1577d1284b6ed1959fb 100644 +index 585a957fd8a1467dc262bd1ca2058584fd8762c9..16ad38c3b7d753c386e091af700d1bebd4c59e3e 100644 --- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp +++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -@@ -1881,7 +1881,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent( +@@ -1875,7 +1875,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent( // Open a minimal popup. *aIsPopupRequested = true; @@ -2683,10 +2562,10 @@ index e3f616c4efd5d7e10ed372afa4b5c4d2d93e6a67..abb7772184c9baf23025c1577d1284b6 /** diff --git a/toolkit/mozapps/update/UpdateService.sys.mjs b/toolkit/mozapps/update/UpdateService.sys.mjs -index 6c2b400952492266a184c96b4a1ce71e87df7ffe..6e1fb4f59b6a6d70100e1eb1d15c937d8480988a 100644 +index eeec31f4d77de0f9622692eeb761392ed54b90ad..8907773fb6212f4e9cc184f87b840c91a0db67b6 100644 --- a/toolkit/mozapps/update/UpdateService.sys.mjs +++ b/toolkit/mozapps/update/UpdateService.sys.mjs -@@ -3894,6 +3894,8 @@ export class UpdateService { +@@ -3811,6 +3811,8 @@ export class UpdateService { } get disabledForTesting() { @@ -2696,10 +2575,10 @@ index 6c2b400952492266a184c96b4a1ce71e87df7ffe..6e1fb4f59b6a6d70100e1eb1d15c937d } diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild -index f42ed17a4a75689ae9c8e769d7b6e2c3f654b8ee..5af0877335339407160dd7d10b89bd3d62adff9f 100644 +index c50b7f3932e18da9fad4b673e353974a001e78c4..708e0d75594ddcd62276d4e08c4bd5c64d7f0698 100644 --- a/toolkit/toolkit.mozbuild +++ b/toolkit/toolkit.mozbuild -@@ -156,6 +156,7 @@ if CONFIG["ENABLE_WEBDRIVER"]: +@@ -152,6 +152,7 @@ if CONFIG["ENABLE_WEBDRIVER"]: "/remote", "/testing/firefox-ui", "/testing/marionette", @@ -2707,6 +2586,22 @@ index f42ed17a4a75689ae9c8e769d7b6e2c3f654b8ee..5af0877335339407160dd7d10b89bd3d "/toolkit/components/telemetry/tests/marionette", ] +diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp +index 795fc8669cc6f03a57139745f58963ffefe5aeff..46651bb0b53be9a522e1deb90140bf386a9f8b51 100644 +--- a/toolkit/xre/nsAppRunner.cpp ++++ b/toolkit/xre/nsAppRunner.cpp +@@ -5633,7 +5633,10 @@ nsresult XREMain::XRE_mainRun() { + + if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) { + #ifdef XP_MACOSX +- if (!BackgroundTasks::IsBackgroundTaskMode()) { ++# if defined(MOZ_BACKGROUNDTASKS) ++ if (!BackgroundTasks::IsBackgroundTaskMode()) ++# endif // defined(MOZ_BACKGROUNDTASKS) ++ { + rv = appStartup->CreateHiddenWindow(); + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + } diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp index 7eb9e1104682d4eb47060654f43a1efa8b2a6bb2..a8315d6decf654b5302bea5beeea34140c300ded 100644 --- a/toolkit/xre/nsWindowsWMain.cpp @@ -2743,10 +2638,10 @@ index 7eb9e1104682d4eb47060654f43a1efa8b2a6bb2..a8315d6decf654b5302bea5beeea3414 // Only run this code if LauncherProcessWin.h was included beforehand, thus // signalling that the hosting process should support launcher mode. diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp -index fe72a2715da8846146377e719559c16e6ef1f7ff..a5959143bac8f62ee359fa3883a844f3fe541685 100644 +index e5cc386651e192710b61858ab5625c97a02b92da..e560ad4fef232a26ce1e1b244f4ccea05f4aea71 100644 --- a/uriloader/base/nsDocLoader.cpp +++ b/uriloader/base/nsDocLoader.cpp -@@ -813,6 +813,12 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, +@@ -812,6 +812,12 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, ("DocLoader:%p: Firing load event for document.open\n", this)); @@ -2760,7 +2655,7 @@ index fe72a2715da8846146377e719559c16e6ef1f7ff..a5959143bac8f62ee359fa3883a844f3 // nsDocumentViewer::LoadComplete that doesn't do various things // that are not relevant here because this wasn't an actual diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp -index 139a43a1780dac34a6d8b135accac9cf39beef3f..2a855c3ae87e4e5a431cb1547cda0ee88490ca33 100644 +index c4dc15918032a34d8be9f1cda94a9375466980f6..20756dc9166f9665d408cd007e9df55b5937b73c 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -112,6 +112,7 @@ @@ -2771,7 +2666,7 @@ index 139a43a1780dac34a6d8b135accac9cf39beef3f..2a855c3ae87e4e5a431cb1547cda0ee8 #include "mozilla/Preferences.h" #include "mozilla/ipc/URIUtils.h" -@@ -872,6 +873,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension( +@@ -864,6 +865,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension( return NS_OK; } @@ -2784,9 +2679,9 @@ index 139a43a1780dac34a6d8b135accac9cf39beef3f..2a855c3ae87e4e5a431cb1547cda0ee8 nsresult nsExternalHelperAppService::GetFileTokenForPath( const char16_t* aPlatformAppPath, nsIFile** aFile) { nsDependentString platformAppPath(aPlatformAppPath); -@@ -1494,7 +1501,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { +@@ -1485,7 +1492,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { // Strip off the ".part" from mTempLeafName - mTempLeafName.Truncate(mTempLeafName.Length() - ArrayLength(".part") + 1); + mTempLeafName.Truncate(mTempLeafName.Length() - std::size(".part") + 1); + return CreateSaverForTempFile(); +} @@ -2797,7 +2692,7 @@ index 139a43a1780dac34a6d8b135accac9cf39beef3f..2a855c3ae87e4e5a431cb1547cda0ee8 mSaver = do_CreateInstance(NS_BACKGROUNDFILESAVERSTREAMLISTENER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); -@@ -1683,7 +1695,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { +@@ -1671,7 +1683,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { return NS_OK; } @@ -2835,7 +2730,7 @@ index 139a43a1780dac34a6d8b135accac9cf39beef3f..2a855c3ae87e4e5a431cb1547cda0ee8 if (NS_FAILED(rv)) { nsresult transferError = rv; -@@ -1744,6 +1785,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { +@@ -1732,6 +1773,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { bool alwaysAsk = true; mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk); @@ -2845,7 +2740,7 @@ index 139a43a1780dac34a6d8b135accac9cf39beef3f..2a855c3ae87e4e5a431cb1547cda0ee8 if (alwaysAsk) { // But we *don't* ask if this mimeInfo didn't come from // our user configuration datastore and the user has said -@@ -2260,6 +2304,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, +@@ -2248,6 +2292,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, NotifyTransfer(aStatus); } @@ -2862,7 +2757,7 @@ index 139a43a1780dac34a6d8b135accac9cf39beef3f..2a855c3ae87e4e5a431cb1547cda0ee8 return NS_OK; } -@@ -2743,6 +2797,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { +@@ -2731,6 +2785,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { } } @@ -2879,7 +2774,7 @@ index 139a43a1780dac34a6d8b135accac9cf39beef3f..2a855c3ae87e4e5a431cb1547cda0ee8 // OnStartRequest) mDialog = nullptr; diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h -index e880b90b2df85fb3b1ab3ba8d2fc181b824e2272..dbadd74dea9b245d68da3b2856e16b7b98c655d0 100644 +index 2dd4ff87bda3e0ba395cca168c42b37db1713ddf..83e8a3d328e325b3f50f593c9ea71692f9c7d401 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h @@ -258,6 +258,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, @@ -2891,7 +2786,7 @@ index e880b90b2df85fb3b1ab3ba8d2fc181b824e2272..dbadd74dea9b245d68da3b2856e16b7b }; /** -@@ -463,6 +465,9 @@ class nsExternalAppHandler final : public nsIStreamListener, +@@ -455,6 +457,9 @@ class nsExternalAppHandler final : public nsIStreamListener, * Upon successful return, both mTempFile and mSaver will be valid. */ nsresult SetUpTempFile(nsIChannel* aChannel); @@ -2973,10 +2868,10 @@ index 1c25e9d9a101233f71e92288a0f93125b81ac1c5..22cf67b0f6e3ddd2b3ed725a314ba6a9 } #endif diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h -index 3d469853bbd30c433ee7b6d2be7175caa568196e..214b92f0a8913fb6667b7554410d4cd58c53cad3 100644 +index c4e510441cf6329b2ad898034fbe39fa1a701ad4..e34d797ee3e3f2985e6d4472afce133e97a0caa4 100644 --- a/widget/MouseEvents.h +++ b/widget/MouseEvents.h -@@ -327,6 +327,9 @@ class WidgetMouseEvent : public WidgetMouseEventBase, +@@ -363,6 +363,9 @@ class WidgetMouseEvent : public WidgetMouseEventBase, // Otherwise, this must be 0. uint32_t mClickCount = 0; @@ -2986,14 +2881,14 @@ index 3d469853bbd30c433ee7b6d2be7175caa568196e..214b92f0a8913fb6667b7554410d4cd5 // Whether the event should ignore scroll frame bounds during dispatch. bool mIgnoreRootScrollFrame = false; -@@ -341,6 +344,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, +@@ -386,6 +389,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, mContextMenuTrigger = aEvent.mContextMenuTrigger; mExitFrom = aEvent.mExitFrom; mClickCount = aEvent.mClickCount; + mJugglerEventId = aEvent.mJugglerEventId; mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame; + mIgnoreCapturingContent = aEvent.mIgnoreCapturingContent; mClickEventPrevented = aEvent.mClickEventPrevented; - } diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm index e4bdf715e2fb899e97a5bfeb2e147127460d6047..3554f919480278b7353617481c7ce8050630a1aa 100644 --- a/widget/cocoa/NativeKeyBindings.mm @@ -3057,6 +2952,18 @@ index e4bdf715e2fb899e97a5bfeb2e147127460d6047..3554f919480278b7353617481c7ce805 break; } if (aEvent.IsMeta()) { +diff --git a/widget/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp +index ad56ab325bb3b3c348259f852453eec1190d892b..272731c25d19e83a2da988ec3176e5227dc4da5b 100644 +--- a/widget/gtk/nsFilePicker.cpp ++++ b/widget/gtk/nsFilePicker.cpp +@@ -21,6 +21,7 @@ + #include "mozilla/Components.h" + #include "mozilla/Preferences.h" + #include "mozilla/dom/Promise.h" ++#include "gfxPlatform.h" + + #include "nsArrayEnumerator.h" + #include "nsEnumeratorUtils.h" diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp index bb4ee9175e66dc40de1871a7f91368fe309494a3..747625e3869882300bfbc18b184db5151dd90c1a 100644 --- a/widget/headless/HeadlessCompositorWidget.cpp @@ -3207,7 +3114,7 @@ index facd2bc65afab8ec1aa322faa20a67464964dfb9..d6dea95472bec6006411753c3dfdab2e } // namespace widget diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp -index c6095751bc1e9bbe907e64fb634b799cac31bb0a..ce1b995015843babeab0e3bf4e357d45066b3cab 100644 +index b8b3f6a09f3fd480f67c28a2d3c6daa960946324..8b9ea637e18c404254ca8a72dabf860452699096 100644 --- a/widget/headless/HeadlessWidget.cpp +++ b/widget/headless/HeadlessWidget.cpp @@ -111,6 +111,8 @@ void HeadlessWidget::Destroy() { @@ -3219,7 +3126,7 @@ index c6095751bc1e9bbe907e64fb634b799cac31bb0a..ce1b995015843babeab0e3bf4e357d45 nsBaseWidget::OnDestroy(); nsBaseWidget::Destroy(); -@@ -613,5 +615,14 @@ nsresult HeadlessWidget::SynthesizeNativeTouchpadPan( +@@ -591,5 +593,14 @@ nsresult HeadlessWidget::SynthesizeNativeTouchpadPan( return NS_OK; } @@ -3235,12 +3142,12 @@ index c6095751bc1e9bbe907e64fb634b799cac31bb0a..ce1b995015843babeab0e3bf4e357d45 } // namespace widget } // namespace mozilla diff --git a/widget/headless/HeadlessWidget.h b/widget/headless/HeadlessWidget.h -index 9856991ef32f25f51942f8cd664a09bec2192c70..948947a421179e91c51005aeb83ed0d18cfc84ce 100644 +index f07f7284495cf5e48409866aaef6fd4d529568be..daefaa8f58c3c8392ce229c814807bc5fff77dc7 100644 --- a/widget/headless/HeadlessWidget.h +++ b/widget/headless/HeadlessWidget.h -@@ -141,6 +141,9 @@ class HeadlessWidget : public nsBaseWidget { - int32_t aModifierFlags, - nsIObserver* aObserver) override; +@@ -136,6 +136,9 @@ class HeadlessWidget : public nsBaseWidget { + int32_t aModifierFlags, + nsIObserver* aObserver) override; + using SnapshotListener = std::function&&)>; + void SetSnapshotListener(SnapshotListener&& listener); @@ -3249,10 +3156,10 @@ index 9856991ef32f25f51942f8cd664a09bec2192c70..948947a421179e91c51005aeb83ed0d1 ~HeadlessWidget(); bool mEnabled; diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h -index 02775a7f27f5697bc33872d997198ce305556970..6c1ae0e371ee012ef47c8e9c74f949da05ad0025 100644 +index a1f48167403f5bfb30a66809ec3e64bea468fa05..eac7fccf3493e162629918462294456e6ee6b6e1 100644 --- a/widget/nsGUIEventIPC.h +++ b/widget/nsGUIEventIPC.h -@@ -234,6 +234,7 @@ struct ParamTraits { +@@ -244,6 +244,7 @@ struct ParamTraits { aParam.mExitFrom.value())); } WriteParam(aWriter, aParam.mClickCount); @@ -3260,7 +3167,7 @@ index 02775a7f27f5697bc33872d997198ce305556970..6c1ae0e371ee012ef47c8e9c74f949da } static bool Read(MessageReader* aReader, paramType* aResult) { -@@ -258,6 +259,7 @@ struct ParamTraits { +@@ -268,6 +269,7 @@ struct ParamTraits { aResult->mExitFrom = Some(static_cast(exitFrom)); } rv = rv && ReadParam(aReader, &aResult->mClickCount); diff --git a/browser_patches/firefox/preferences/playwright.cfg b/browser_patches/firefox/preferences/playwright.cfg index 1eb51a0fdbc62..db47c4f0c39e4 100644 --- a/browser_patches/firefox/preferences/playwright.cfg +++ b/browser_patches/firefox/preferences/playwright.cfg @@ -88,6 +88,10 @@ pref("geo.provider.testing", true); // THESE ARE NICHE PROPERTIES THAT ARE NICE TO HAVE // ================================================================= +// We never want to have interactive screen capture picker enabled in FF build. +pref("media.getdisplaymedia.screencapturekit.enabled", false); +pref("media.getdisplaymedia.screencapturekit.picker.enabled", false); + // Enable software-backed webgl. See https://phabricator.services.mozilla.com/D164016 pref("webgl.forbid-software", false); diff --git a/browser_patches/webkit/UPSTREAM_CONFIG.sh b/browser_patches/webkit/UPSTREAM_CONFIG.sh index 3fb94ec302ace..ddac1019b9811 100644 --- a/browser_patches/webkit/UPSTREAM_CONFIG.sh +++ b/browser_patches/webkit/UPSTREAM_CONFIG.sh @@ -1,3 +1,3 @@ REMOTE_URL="https://github.com/WebKit/WebKit.git" BASE_BRANCH="main" -BASE_REVISION="8ceb1da47e75a488ae4c12017a861636904acd4f" +BASE_REVISION="71b1107b4656f116936a278cb4948cc2db56998c" diff --git a/browser_patches/webkit/embedder/Playwright/mac/AppDelegate.m b/browser_patches/webkit/embedder/Playwright/mac/AppDelegate.m index f9708d364df3d..b4d08b700ac91 100644 --- a/browser_patches/webkit/embedder/Playwright/mac/AppDelegate.m +++ b/browser_patches/webkit/embedder/Playwright/mac/AppDelegate.m @@ -33,6 +33,7 @@ #import #import #import +#import #import #import #import @@ -240,6 +241,8 @@ - (WKWebViewConfiguration *)defaultConfiguration configuration.preferences._hiddenPageDOMTimerThrottlingAutoIncreases = NO; configuration.preferences._pageVisibilityBasedProcessSuppressionEnabled = NO; configuration.preferences._domTimersThrottlingEnabled = NO; + // Do not auto play audio and video with sound. + configuration.defaultWebpagePreferences._autoplayPolicy = _WKWebsiteAutoplayPolicyAllowWithoutSound; _WKProcessPoolConfiguration *processConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease]; processConfiguration.forceOverlayScrollbars = YES; configuration.processPool = [[[WKProcessPool alloc] _initWithConfiguration:processConfiguration] autorelease]; diff --git a/browser_patches/webkit/patches/bootstrap.diff b/browser_patches/webkit/patches/bootstrap.diff index ea833df5fdd3e..a067098b83aa0 100644 --- a/browser_patches/webkit/patches/bootstrap.diff +++ b/browser_patches/webkit/patches/bootstrap.diff @@ -1,8 +1,8 @@ diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt -index db9554ed7eb6ddb62de1bc549a8e7c50944c7869..b6ce1761f11281c6362790ee59d83feed6f717cf 100644 +index 37aca585f67028500a828354396c9e59ccfe273d..f32c64abe10c08b44a75b4682ab2885a4d258799 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt -@@ -1398,22 +1398,27 @@ set(JavaScriptCore_INSPECTOR_DOMAINS +@@ -1402,22 +1402,27 @@ set(JavaScriptCore_INSPECTOR_DOMAINS ${JAVASCRIPTCORE_DIR}/inspector/protocol/CSS.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Canvas.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Console.json @@ -31,10 +31,10 @@ index db9554ed7eb6ddb62de1bc549a8e7c50944c7869..b6ce1761f11281c6362790ee59d83fee ${JAVASCRIPTCORE_DIR}/inspector/protocol/ServiceWorker.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Target.json diff --git a/Source/JavaScriptCore/DerivedSources-input.xcfilelist b/Source/JavaScriptCore/DerivedSources-input.xcfilelist -index eebcd3f03aeb560fd70ab52b325e21c5ced74321..340323566ea7c8f5d85303c7adb4570913a41451 100644 +index 7b9566ebe6355e6cb853e59a478a17a29953e856..a8d3266e69c4700a8b5ed806f456e8d1bc3194b9 100644 --- a/Source/JavaScriptCore/DerivedSources-input.xcfilelist +++ b/Source/JavaScriptCore/DerivedSources-input.xcfilelist -@@ -99,21 +99,26 @@ $(PROJECT_DIR)/inspector/protocol/CPUProfiler.json +@@ -100,21 +100,26 @@ $(PROJECT_DIR)/inspector/protocol/CPUProfiler.json $(PROJECT_DIR)/inspector/protocol/CSS.json $(PROJECT_DIR)/inspector/protocol/Canvas.json $(PROJECT_DIR)/inspector/protocol/Console.json @@ -62,10 +62,10 @@ index eebcd3f03aeb560fd70ab52b325e21c5ced74321..340323566ea7c8f5d85303c7adb45709 $(PROJECT_DIR)/inspector/protocol/Security.json $(PROJECT_DIR)/inspector/protocol/ServiceWorker.json diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make -index 99dd36c7234cecd9c6620c94c4e6e93ff6548d77..d2017ded67f3e811d0f905be238c73ccb0348aa7 100644 +index 103f0b77b93558944be1770a00e1a149d7257812..a580b33ea9a7f2f74547f77c1dab4caa019dce81 100644 --- a/Source/JavaScriptCore/DerivedSources.make +++ b/Source/JavaScriptCore/DerivedSources.make -@@ -299,22 +299,27 @@ INSPECTOR_DOMAINS := \ +@@ -303,22 +303,27 @@ INSPECTOR_DOMAINS := \ $(JavaScriptCore)/inspector/protocol/CSS.json \ $(JavaScriptCore)/inspector/protocol/Canvas.json \ $(JavaScriptCore)/inspector/protocol/Console.json \ @@ -121,19 +121,19 @@ index 9bc5d1fd8e2a7e576be046b3c6ae1266696cf552..610f810db1dd6865c500c0796386a828 { return addPrefixToIdentifier(++s_lastUsedIdentifier); diff --git a/Source/JavaScriptCore/inspector/IdentifiersFactory.h b/Source/JavaScriptCore/inspector/IdentifiersFactory.h -index eb25aedee4cd9ebe007e06c2515b37ee095b06f4..badf6559595c8377db1089ca3c25008e1be2c8f1 100644 +index 4113ddb45d4a8d08379d4dc56c44cde56162accf..e00cb9cb01a7a241f3f25b1e4cdc2fcaee92b3ac 100644 --- a/Source/JavaScriptCore/inspector/IdentifiersFactory.h +++ b/Source/JavaScriptCore/inspector/IdentifiersFactory.h @@ -31,6 +31,7 @@ namespace Inspector { - class JS_EXPORT_PRIVATE IdentifiersFactory { + class IdentifiersFactory { public: -+ static void initializeWithProcessID(uint64_t); - static String createIdentifier(); - static String requestId(unsigned long identifier); ++ JS_EXPORT_PRIVATE static void initializeWithProcessID(uint64_t); + JS_EXPORT_PRIVATE static String createIdentifier(); + JS_EXPORT_PRIVATE static String requestId(unsigned long identifier); }; diff --git a/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp b/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp -index 143135027999755614d5fae2b897d8dd5e62d611..a357963f3350d29ea0fd90a20ac2393ff6a0efa9 100644 +index 8b39848154ecab9f7daa2d21c85562a319cd06d7..c8a1f44cb4516993899ffe1404b6c3865d42433a 100644 --- a/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp +++ b/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp @@ -85,7 +85,10 @@ static RefPtr jsToInspectorValue(JSC::JSGlobalObject* globalObject, @@ -149,10 +149,10 @@ index 143135027999755614d5fae2b897d8dd5e62d611..a357963f3350d29ea0fd90a20ac2393f return nullptr; inspectorObject->setValue(name.string(), inspectorValue.releaseNonNull()); diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp -index 3b2056bf5a71301383e0895d77cc6f16842235a9..eaf73171ce70ac43abbe404122a263ce708bb41f 100644 +index 1f5d0adbf624bd24ef1e525967e6e82e8c37b4e5..4fe0f364b4ccd11774bf29f772e0a568549a4322 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp -@@ -100,7 +100,7 @@ void BackendDispatcher::registerDispatcherForDomain(const String& domain, Supple +@@ -102,7 +102,7 @@ void BackendDispatcher::registerDispatcherForDomain(const String& domain, Supple m_dispatchers.set(domain, dispatcher); } @@ -161,7 +161,7 @@ index 3b2056bf5a71301383e0895d77cc6f16842235a9..eaf73171ce70ac43abbe404122a263ce { Ref protect(*this); -@@ -145,6 +145,9 @@ void BackendDispatcher::dispatch(const String& message) +@@ -147,6 +147,9 @@ void BackendDispatcher::dispatch(const String& message) requestId = *requestIdInt; } @@ -172,18 +172,19 @@ index 3b2056bf5a71301383e0895d77cc6f16842235a9..eaf73171ce70ac43abbe404122a263ce // We could be called re-entrantly from a nested run loop, so restore the previous id. SetForScope scopedRequestId(m_currentRequestId, requestId); diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h -index 0c83a1c3baa3bdbb30e53c11aaafd8bda34309cd..127616bbdb65b0867266e5bd6a63bd5a58212870 100644 +index 2eba743177c016a3415d4a5deafc552e842dd0fa..939d14be7a2703777652467f0f60e67ef1c5e0f8 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h -@@ -84,7 +84,10 @@ public: +@@ -83,8 +83,11 @@ public: + ServerError }; - void registerDispatcherForDomain(const String& domain, SupplementalBackendDispatcher*); -- void dispatch(const String& message); -+ + enum class InterceptionResult { Intercepted, Continue }; + using Interceptor = WTF::Function&)>; -+ void dispatch(const String& message, Interceptor&& interceptor = Interceptor()); ++ + JS_EXPORT_PRIVATE void registerDispatcherForDomain(const String& domain, SupplementalBackendDispatcher*); +- JS_EXPORT_PRIVATE void dispatch(const String& message); ++ JS_EXPORT_PRIVATE void dispatch(const String& message, Interceptor&& interceptor = Interceptor()); // Note that 'unused' is a workaround so the compiler can pick the right sendResponse based on arity. // When is fixed or this class is renamed for the JSON::Object case, @@ -222,7 +223,7 @@ index 0cc2127c9c12c2d82dea9550bad73f4ffb99ba24..8ca65cc042d435cbc0e05dcc5c5dfc95 } diff --git a/Source/JavaScriptCore/inspector/InspectorTarget.h b/Source/JavaScriptCore/inspector/InspectorTarget.h -index 082dd93cb0505c5bc7a2d5a7cf78fa0306809082..3f50f49ef9e691b3dc57dafd66c1e7d323736f40 100644 +index b555c2e5a071d0a6a016061cc60755449557556d..d019346f0932296d15212c76a4a9b56beb565ff4 100644 --- a/Source/JavaScriptCore/inspector/InspectorTarget.h +++ b/Source/JavaScriptCore/inspector/InspectorTarget.h @@ -66,8 +66,12 @@ public: @@ -367,25 +368,10 @@ index e47c6ca59f37fbf18ca8a393df72e0472363fabd..b393465540595220561ae00afb854082 void InspectorTargetAgent::didCommitProvisionalTarget(const String& oldTargetID, const String& committedTargetID) diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h -index 1ccce5707ca2a4743029614777bb6b9938f8a09c..cbb3466a855887d4dac3a6064e5de6ead051c1a6 100644 +index 04377b714a6ccb5294c65d592e74350621d470ba..b6de937bfa3e6185ce29f4e432d327a3cedee6df 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h +++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h -@@ -37,12 +37,12 @@ namespace Inspector { - - class InspectorTarget; - --class InspectorTargetAgent final : public InspectorAgentBase, public TargetBackendDispatcherHandler, public CanMakeCheckedPtr { -+class JS_EXPORT_PRIVATE InspectorTargetAgent final : public InspectorAgentBase, public TargetBackendDispatcherHandler, public CanMakeCheckedPtr { - WTF_MAKE_NONCOPYABLE(InspectorTargetAgent); - WTF_MAKE_TZONE_ALLOCATED(InspectorTargetAgent); - WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(InspectorTargetAgent); - public: -- JS_EXPORT_PRIVATE InspectorTargetAgent(FrontendRouter&, BackendDispatcher&); -+ InspectorTargetAgent(FrontendRouter&, BackendDispatcher&); - ~InspectorTargetAgent() final; - - // InspectorAgentBase -@@ -53,14 +53,19 @@ public: +@@ -53,8 +53,11 @@ public: Protocol::ErrorStringOr setPauseOnStart(bool) final; Protocol::ErrorStringOr resume(const String& targetId) final; Protocol::ErrorStringOr sendMessageToTarget(const String& targetId, const String& message) final; @@ -393,22 +379,20 @@ index 1ccce5707ca2a4743029614777bb6b9938f8a09c..cbb3466a855887d4dac3a6064e5de6ea + Protocol::ErrorStringOr close(const String& targetId, std::optional&& runBeforeUnload) override; // Target lifecycle. -- JS_EXPORT_PRIVATE void targetCreated(InspectorTarget&); -- JS_EXPORT_PRIVATE void targetDestroyed(InspectorTarget&); -- JS_EXPORT_PRIVATE void didCommitProvisionalTarget(const String& oldTargetID, const String& committedTargetID); -+ void targetCreated(InspectorTarget&); -+ void targetDestroyed(InspectorTarget&); + void targetCrashed(InspectorTarget&); -+ void didCommitProvisionalTarget(const String& oldTargetID, const String& committedTargetID); - + void targetCreated(InspectorTarget&); + void targetDestroyed(InspectorTarget&); + void didCommitProvisionalTarget(const String& oldTargetID, const String& committedTargetID); +@@ -62,6 +65,9 @@ public: // Target messages. -- JS_EXPORT_PRIVATE void sendMessageFromTargetToFrontend(const String& targetId, const String& message); -+ void sendMessageFromTargetToFrontend(const String& targetId, const String& message); -+ -+ bool isConnected() { return m_isConnected; } + void sendMessageFromTargetToFrontend(const String& targetId, const String& message); ++ bool shouldPauseOnStart() const { return m_shouldPauseOnStart; } ++ bool isConnected() { return m_isConnected; } ++ private: // FrontendChannel + FrontendChannel::ConnectionType connectionType() const; diff --git a/Source/JavaScriptCore/inspector/protocol/DOM.json b/Source/JavaScriptCore/inspector/protocol/DOM.json index 27c65fbda226f1cd5bfd68944fe87fb9b2a688a6..b036f050859ee88004a7bf6daa4bb73835360615 100644 --- a/Source/JavaScriptCore/inspector/protocol/DOM.json @@ -903,10 +887,10 @@ index 96af27ece2ac200e11c4311b3ca0d9d3b5a048da..3168f7806fcbdabec07acc5e304bae1e ], "events": [ diff --git a/Source/JavaScriptCore/inspector/protocol/Page.json b/Source/JavaScriptCore/inspector/protocol/Page.json -index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c6462bbff82 100644 +index 3d032713a7f3bb9645bfc7d42455a0494b5376c0..913dda5e90b86cc5f8e4ca6881f6db57520a7f66 100644 --- a/Source/JavaScriptCore/inspector/protocol/Page.json +++ b/Source/JavaScriptCore/inspector/protocol/Page.json -@@ -20,7 +20,14 @@ +@@ -20,7 +20,15 @@ "ScriptEnabled", "ShowDebugBorders", "ShowRepaintCounter", @@ -918,11 +902,12 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 + "NotificationsEnabled", + "FullScreenEnabled", + "InputTypeMonthEnabled", -+ "InputTypeWeekEnabled" ++ "InputTypeWeekEnabled", ++ "FixedBackgroundsPaintRelativeToDocument" ] }, { -@@ -62,6 +69,12 @@ +@@ -62,6 +70,12 @@ "enum": ["None", "Lax", "Strict"], "description": "Same-Site policy of a cookie." }, @@ -935,9 +920,9 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 { "id": "Frame", "type": "object", -@@ -125,6 +138,50 @@ - { "name": "secure", "type": "boolean", "description": "True if cookie is secure." }, - { "name": "sameSite", "$ref": "CookieSameSitePolicy", "description": "Cookie Same-Site policy." } +@@ -126,6 +140,50 @@ + { "name": "sameSite", "$ref": "CookieSameSitePolicy", "description": "Cookie Same-Site policy." }, + { "name": "partitionKey", "type": "string", "optional": true, "description": "Cookie partition key. If null and partitioned property is true, then key must be computed." } ] + }, + { @@ -986,7 +971,7 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 } ], "commands": [ -@@ -144,6 +201,14 @@ +@@ -145,6 +203,14 @@ { "name": "revalidateAllResources", "type": "boolean", "optional": true, "description": "If true, all cached subresources will be revalidated when the main resource loads. Otherwise, only expired cached subresources will be revalidated (the default behavior for most WebKit clients)." } ] }, @@ -1001,7 +986,7 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 { "name": "navigate", "description": "Navigates current page to the given URL.", -@@ -160,6 +225,14 @@ +@@ -161,6 +227,14 @@ { "name": "value", "type": "string", "optional": true, "description": "Value to override the user agent with. If this value is not provided, the override is removed. Overrides are removed when Web Inspector closes/disconnects." } ] }, @@ -1016,7 +1001,7 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 { "name": "overrideSetting", "description": "Allows the frontend to override the inspected page's settings.", -@@ -283,6 +356,28 @@ +@@ -285,6 +359,28 @@ { "name": "media", "type": "string", "description": "Media type to emulate. Empty string disables the override." } ] }, @@ -1045,7 +1030,7 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 { "name": "snapshotNode", "description": "Capture a snapshot of the specified node that does not include unrelated layers.", -@@ -303,7 +398,8 @@ +@@ -305,7 +401,8 @@ { "name": "y", "type": "integer", "description": "Y coordinate" }, { "name": "width", "type": "integer", "description": "Rectangle width" }, { "name": "height", "type": "integer", "description": "Rectangle height" }, @@ -1055,7 +1040,7 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 ], "returns": [ { "name": "dataURL", "type": "string", "description": "Base64-encoded image data (PNG)." } -@@ -321,12 +417,64 @@ +@@ -323,12 +420,64 @@ { "name": "setScreenSizeOverride", "description": "Overrides screen size exposed to DOM and used in media queries for testing with provided values.", @@ -1121,7 +1106,7 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 } ], "events": [ -@@ -334,14 +482,16 @@ +@@ -336,14 +485,16 @@ "name": "domContentEventFired", "targetTypes": ["page"], "parameters": [ @@ -1140,7 +1125,7 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 ] }, { -@@ -351,6 +501,14 @@ +@@ -353,6 +504,14 @@ { "name": "frame", "$ref": "Frame", "description": "Frame object." } ] }, @@ -1155,7 +1140,7 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 { "name": "frameDetached", "description": "Fired when frame has been detached from its parent.", -@@ -379,7 +537,8 @@ +@@ -381,7 +540,8 @@ "targetTypes": ["page"], "parameters": [ { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has scheduled a navigation." }, @@ -1165,7 +1150,7 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 ] }, { -@@ -390,6 +549,22 @@ +@@ -392,6 +552,22 @@ { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has cleared its scheduled navigation." } ] }, @@ -1188,7 +1173,7 @@ index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..829bd459b62568e73fadd806adc14c64 { "name": "defaultUserPreferencesDidChange", "description": "Fired when the default value of a user preference changes at the system level.", -@@ -397,6 +572,42 @@ +@@ -399,6 +575,42 @@ "parameters": [ { "name": "preferences", "type": "array", "items": { "$ref": "UserPreference" }, "description": "List of user preferences that can be overriden and their new system (default) values." } ] @@ -1694,18 +1679,6 @@ index 52920cded24a9c6b0ef6fb4e518664955db4f9fa..bbbabc4e7259088b9404e8cc07eecd6f ] }, { -diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp -index 7c2ecd2c9afe3882903a590a76504d98da49f0af..9472d74977234a97e7ede76a042e22884c492594 100644 ---- a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp -+++ b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp -@@ -28,7 +28,6 @@ - - #include "CodeBlock.h" - #include "JSCInlines.h" --#include "ProfilerDumper.h" - #include - - namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/runtime/ConsoleClient.h b/Source/JavaScriptCore/runtime/ConsoleClient.h index 24891ad836086fd23024fcb4d08ca63f6974c812..29f4b6b1923383fec7a99d28a4e815dc4536d160 100644 --- a/Source/JavaScriptCore/runtime/ConsoleClient.h @@ -1719,18 +1692,10 @@ index 24891ad836086fd23024fcb4d08ca63f6974c812..29f4b6b1923383fec7a99d28a4e815dc private: enum ArgumentRequirement { ArgumentRequired, ArgumentNotRequired }; diff --git a/Source/ThirdParty/libwebrtc/CMakeLists.txt b/Source/ThirdParty/libwebrtc/CMakeLists.txt -index 2557956d875e6d5be0d83368f4eaaa8083585c26..da7bde1dc256e9e1f4d13469e150970f5090a993 100644 +index d21b38eb4e5f27c12ca755799669883e71ce6de2..89cebf78b4599e5595ba570286a82e6aaa0f0f38 100644 --- a/Source/ThirdParty/libwebrtc/CMakeLists.txt +++ b/Source/ThirdParty/libwebrtc/CMakeLists.txt -@@ -453,6 +453,7 @@ set(webrtc_SOURCES - Source/third_party/boringssl/src/crypto/x509/x_val.c - Source/third_party/boringssl/src/crypto/x509/x_x509a.c - Source/third_party/boringssl/src/crypto/x509/x_x509.c -+ - Source/third_party/boringssl/src/decrepit/bio/base64_bio.c - Source/third_party/boringssl/src/decrepit/blowfish/blowfish.c - Source/third_party/boringssl/src/decrepit/cast/cast.c -@@ -532,6 +533,11 @@ set(webrtc_SOURCES +@@ -532,6 +532,11 @@ set(webrtc_SOURCES Source/third_party/crc32c/src/src/crc32c.cc Source/third_party/crc32c/src/src/crc32c_portable.cc Source/third_party/crc32c/src/src/crc32c_sse42.cc @@ -1742,13 +1707,22 @@ index 2557956d875e6d5be0d83368f4eaaa8083585c26..da7bde1dc256e9e1f4d13469e150970f Source/third_party/libyuv/source/compare.cc Source/third_party/libyuv/source/compare_common.cc Source/third_party/libyuv/source/compare_gcc.cc -@@ -2406,6 +2412,10 @@ set(webrtc_INCLUDE_DIRECTORIES PRIVATE +@@ -695,7 +700,6 @@ set(webrtc_SOURCES + Source/webrtc/api/video_codecs/builtin_video_encoder_factory.cc + Source/webrtc/api/video_codecs/h264_profile_level_id.cc + Source/webrtc/api/video_codecs/h265_profile_tier_level.cc +- Source/webrtc/api/video_codecs/libaom_av1_encoder_factory.cc + Source/webrtc/api/video_codecs/scalability_mode.cc + Source/webrtc/api/video_codecs/scalability_mode_helper.cc + Source/webrtc/api/video_codecs/sdp_video_format.cc +@@ -2354,6 +2358,11 @@ set(webrtc_INCLUDE_DIRECTORIES PRIVATE Source/third_party/libsrtp/config Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include +# Playwright begin + Source/third_party/libwebm + Source/third_party/libvpx/source/libvpx ++ Source/third_party/libvpx/source/libvpx/third_party/googletest/src/include +# Playwright end Source/third_party/libyuv/include Source/third_party/opus/src/celt @@ -1767,22 +1741,14 @@ index 0c5c8e689bdddec766f9de5bffd4444a5e068d77..330dd1f585e530722178c65c883641a2 // FIXME: Set WEBRTC_USE_BUILTIN_ISAC_FIX and WEBRTC_USE_BUILTIN_ISAC_FLOAT for iOS and Mac diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp -index fe9c7b3f648392219fdf5be8d2bab99e1b4959e4..def7770bc94a1f533add081e907826058f169bbe 100644 +index 6c754858a3ea883a65ad022ce16b6c45ae65ee35..15f968472712e1a2a88672ed290b103cf9d620ec 100644 --- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp +++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp -@@ -403,3 +403,24 @@ __ZN3rtc15CountIPMaskBitsERKNS_9IPAddressE - __ZN3rtc19IPAddressPrecedenceERKNS_9IPAddressE - __ZNK3rtc16InterfaceAddresseqERKS0_ - __ZNK3rtc16InterfaceAddress8ToStringEv -+__ZN8mkvmuxer11SegmentInfo15set_writing_appEPKc +@@ -421,3 +421,16 @@ __ZNK8mkvmuxer7Segment16GetTrackByNumberEy + __ZN8mkvmuxer6Tracks11kAv1CodecIdE + __ZN8mkvmuxer6Tracks11kVp8CodecIdE + __ZN8mkvmuxer6Tracks11kVp9CodecIdE +__ZN8mkvmuxer11SegmentInfo4InitEv -+__ZN8mkvmuxer7Segment10OutputCuesEb -+__ZN8mkvmuxer7Segment13AddVideoTrackEiii -+__ZN8mkvmuxer7Segment4InitEPNS_10IMkvWriterE -+__ZN8mkvmuxer7Segment8AddFrameEPKhyyyb -+__ZN8mkvmuxer7Segment8FinalizeEv -+__ZN8mkvmuxer7SegmentC1Ev -+__ZN8mkvmuxer7SegmentD1Ev +__ZN8mkvmuxer9MkvWriterC1EP7__sFILE +_ARGBToI420 +_vpx_codec_destroy @@ -1795,32 +1761,8 @@ index fe9c7b3f648392219fdf5be8d2bab99e1b4959e4..def7770bc94a1f533add081e90782605 +_vpx_codec_iface_name +_vpx_codec_version_str +_vpx_codec_vp8_cx -diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc -index 9ada3cdc5f6ceecabdc4b17998754a7bf3adb0e9..1136def8438ec98a8f96bfd67fd9b0691bb3ffaf 100644 ---- a/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc -+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc -@@ -16,6 +16,7 @@ - #include "absl/algorithm/container.h" - #include "absl/memory/memory.h" - #include "absl/types/optional.h" -+#include "api/call/transport.h" - #include "api/video/video_bitrate_allocation.h" - #include "modules/rtp_rtcp/include/receive_statistics.h" - #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" -diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h b/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h -index f95c3b6c6b73a01974f26d88bcc533e5032ddb66..6a9368c60824cd32649c93286522d779cac59bd2 100644 ---- a/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h -+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/modules/rtp_rtcp/source/rtp_format_h264.h -@@ -16,6 +16,7 @@ - - #include - #include -+#include - #include - - #include "api/array_view.h" diff --git a/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj b/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj -index 4450f961579b52a88876cfc2d72a59bab4ccb863..4a217d81585ce495237aa013d3ace98a7bee394e 100644 +index 635e7cd52a3eae41c82d989cda47563d0750dab5..8a10d9970972598bf270e12cce5fd55066c8fede 100644 --- a/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj +++ b/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj @@ -35,6 +35,20 @@ @@ -1844,17 +1786,7 @@ index 4450f961579b52a88876cfc2d72a59bab4ccb863..4a217d81585ce495237aa013d3ace98a /* Begin PBXBuildFile section */ 2D6BFF60280A93DF00A1A74F /* video_coding.h in Headers */ = {isa = PBXBuildFile; fileRef = 4131C45B234C81710028A615 /* video_coding.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2D6BFF61280A93EC00A1A74F /* video_codec_initializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4131C45E234C81720028A615 /* video_codec_initializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; -@@ -5144,6 +5158,9 @@ - DDF30D9127C5C725006A526F /* receive_side_congestion_controller.h in Headers */ = {isa = PBXBuildFile; fileRef = DDF30D9027C5C725006A526F /* receive_side_congestion_controller.h */; }; - DDF30D9527C5C756006A526F /* bwe_defines.h in Headers */ = {isa = PBXBuildFile; fileRef = DDF30D9327C5C756006A526F /* bwe_defines.h */; }; - DDF30D9627C5C756006A526F /* remote_bitrate_estimator.h in Headers */ = {isa = PBXBuildFile; fileRef = DDF30D9427C5C756006A526F /* remote_bitrate_estimator.h */; }; -+ F3B7819924C7CC5200FCB122 /* mkvmuxerutil.cc in Sources */ = {isa = PBXBuildFile; fileRef = F3B7819624C7CC5100FCB122 /* mkvmuxerutil.cc */; }; -+ F3B7819A24C7CC5200FCB122 /* mkvmuxer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F3B7819724C7CC5200FCB122 /* mkvmuxer.cc */; }; -+ F3B7819B24C7CC5200FCB122 /* mkvwriter.cc in Sources */ = {isa = PBXBuildFile; fileRef = F3B7819824C7CC5200FCB122 /* mkvwriter.cc */; }; - /* End PBXBuildFile section */ - - /* Begin PBXBuildRule section */ -@@ -5632,6 +5649,13 @@ +@@ -5618,6 +5632,13 @@ remoteGlobalIDString = DDF30D0527C5C003006A526F; remoteInfo = absl; }; @@ -1868,42 +1800,7 @@ index 4450f961579b52a88876cfc2d72a59bab4ccb863..4a217d81585ce495237aa013d3ace98a /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ -@@ -11217,6 +11241,9 @@ - DDF30D9027C5C725006A526F /* receive_side_congestion_controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = receive_side_congestion_controller.h; sourceTree = ""; }; - DDF30D9327C5C756006A526F /* bwe_defines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bwe_defines.h; sourceTree = ""; }; - DDF30D9427C5C756006A526F /* remote_bitrate_estimator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remote_bitrate_estimator.h; sourceTree = ""; }; -+ F3B7819624C7CC5100FCB122 /* mkvmuxerutil.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mkvmuxerutil.cc; path = mkvmuxer/mkvmuxerutil.cc; sourceTree = ""; }; -+ F3B7819724C7CC5200FCB122 /* mkvmuxer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mkvmuxer.cc; path = mkvmuxer/mkvmuxer.cc; sourceTree = ""; }; -+ F3B7819824C7CC5200FCB122 /* mkvwriter.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mkvwriter.cc; path = mkvmuxer/mkvwriter.cc; sourceTree = ""; }; - FB39D0D11200F0E300088E69 /* libwebrtc.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libwebrtc.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; - /* End PBXFileReference section */ - -@@ -20069,6 +20096,7 @@ - isa = PBXGroup; - children = ( - CDFD2F9224C4B2F90048DAC3 /* common */, -+ F3B7819524C7CC1300FCB122 /* mkvmuxer */, - CDEBB19224C0191800ADBD44 /* webm_parser */, - ); - path = libwebm; -@@ -20480,6 +20508,16 @@ - path = include; - sourceTree = ""; - }; -+ F3B7819524C7CC1300FCB122 /* mkvmuxer */ = { -+ isa = PBXGroup; -+ children = ( -+ F3B7819724C7CC5200FCB122 /* mkvmuxer.cc */, -+ F3B7819624C7CC5100FCB122 /* mkvmuxerutil.cc */, -+ F3B7819824C7CC5200FCB122 /* mkvwriter.cc */, -+ ); -+ name = mkvmuxer; -+ sourceTree = ""; -+ }; - FB39D06E1200ED9200088E69 = { - isa = PBXGroup; - children = ( -@@ -23772,6 +23810,7 @@ +@@ -23874,6 +23895,7 @@ ); dependencies = ( 410B3827292B73E90003E515 /* PBXTargetDependency */, @@ -1911,7 +1808,7 @@ index 4450f961579b52a88876cfc2d72a59bab4ccb863..4a217d81585ce495237aa013d3ace98a DD2E76E827C6B69A00F2A74C /* PBXTargetDependency */, CDEBB4CC24C01AB400ADBD44 /* PBXTargetDependency */, 411ED040212E0811004320BA /* PBXTargetDependency */, -@@ -23854,6 +23893,7 @@ +@@ -23956,6 +23978,7 @@ 4460B8B92B155B6A00392062 /* vp9_qp_parser_fuzzer */, 444A6EF02AEADFC9005FE121 /* vp9_replay_fuzzer */, 44945C512B9BA1C300447FFD /* webm_fuzzer */, @@ -1919,9 +1816,9 @@ index 4450f961579b52a88876cfc2d72a59bab4ccb863..4a217d81585ce495237aa013d3ace98a ); }; /* End PBXProject section */ -@@ -23937,6 +23977,23 @@ +@@ -24059,6 +24082,23 @@ shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Scripts/create-symlink-to-altroot.sh\"\n"; + shellScript = "[ -z \"${WK_DERIVED_SDK_HEADERS_DIR}\" -o -d \"${WK_DERIVED_SDK_HEADERS_DIR}\" ] && touch \"${SCRIPT_OUTPUT_FILE_0}\"\n"; }; + F31720B127FE216400EEE407 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; @@ -1943,17 +1840,7 @@ index 4450f961579b52a88876cfc2d72a59bab4ccb863..4a217d81585ce495237aa013d3ace98a /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ -@@ -25924,6 +25981,9 @@ - 5CDD865E1E43B8B500621E92 /* min_max_operations.c in Sources */, - 4189395B242A71F5007FDC41 /* min_video_bitrate_experiment.cc in Sources */, - 41B8D8FB28CB85CB00E5FA37 /* missing_mandatory_parameter_cause.cc in Sources */, -+ F3B7819A24C7CC5200FCB122 /* mkvmuxer.cc in Sources */, -+ F3B7819924C7CC5200FCB122 /* mkvmuxerutil.cc in Sources */, -+ F3B7819B24C7CC5200FCB122 /* mkvwriter.cc in Sources */, - 4131C387234B957D0028A615 /* moving_average.cc in Sources */, - 41FCBB1521B1F7AA00A5DF27 /* moving_average.cc in Sources */, - 5CD286101E6A64C90094FDC8 /* moving_max.cc in Sources */, -@@ -26796,6 +26856,11 @@ +@@ -26874,6 +26914,11 @@ target = DDF30D0527C5C003006A526F /* absl */; targetProxy = DD2E76E727C6B69A00F2A74C /* PBXContainerItemProxy */; }; @@ -1965,7 +1852,7 @@ index 4450f961579b52a88876cfc2d72a59bab4ccb863..4a217d81585ce495237aa013d3ace98a /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ -@@ -27371,6 +27436,27 @@ +@@ -27449,6 +27494,27 @@ }; name = Production; }; @@ -1993,7 +1880,7 @@ index 4450f961579b52a88876cfc2d72a59bab4ccb863..4a217d81585ce495237aa013d3ace98a FB39D0711200ED9200088E69 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 5D7C59C71208C68B001C873E /* DebugRelease.xcconfig */; -@@ -27673,6 +27759,16 @@ +@@ -27751,6 +27817,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Production; }; @@ -2010,19 +1897,40 @@ index 4450f961579b52a88876cfc2d72a59bab4ccb863..4a217d81585ce495237aa013d3ace98a FB39D0731200ED9200088E69 /* Build configuration list for PBXProject "libwebrtc" */ = { isa = XCConfigurationList; buildConfigurations = ( +diff --git a/Source/ThirdParty/skia/CMakeLists.txt b/Source/ThirdParty/skia/CMakeLists.txt +index b7e56daffbaac1c8c5bc94bd76826fea1826918b..5365dbfeae72ce5dc6be37e2f07a973bccddfd78 100644 +--- a/Source/ThirdParty/skia/CMakeLists.txt ++++ b/Source/ThirdParty/skia/CMakeLists.txt +@@ -10,6 +10,8 @@ if (USE_SKIA_ENCODERS) + find_package(WebP REQUIRED COMPONENTS mux) + endif () + ++find_package(Threads REQUIRED) ++ + if (ANDROID) + find_package(EXPAT REQUIRED) + endif () +@@ -1054,6 +1056,7 @@ endif () + target_link_libraries(Skia PRIVATE + JPEG::JPEG + PNG::PNG ++ Threads::Threads + ) + + WEBKIT_ADD_TARGET_CXX_FLAGS(Skia diff --git a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml -index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70506b415d 100644 +index a18d2cc93197ef89e9148907cdc47cf7c4359085..d377bee3c2c192e1ed6021684077078903bf422d 100644 --- a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml +++ b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml -@@ -607,6 +607,7 @@ ApplePayEnabled: - default: false +@@ -628,6 +628,7 @@ ApplePayEnabled: + richJavaScript: true # FIXME: This is on by default in WebKit2 PLATFORM(COCOA). Perhaps we should consider turning it on for WebKitLegacy as well. +# Playwright: enable on all platforms to align with Safari. AsyncClipboardAPIEnabled: type: bool status: mature -@@ -617,7 +618,7 @@ AsyncClipboardAPIEnabled: +@@ -638,7 +639,7 @@ AsyncClipboardAPIEnabled: default: false WebKit: "PLATFORM(COCOA) || PLATFORM(GTK)" : true @@ -2031,7 +1939,21 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 WebCore: default: false -@@ -2046,6 +2047,7 @@ CrossOriginEmbedderPolicyEnabled: +@@ -883,13 +884,10 @@ BlobFileAccessEnforcementEnabled: + sharedPreferenceForWebProcess: true + defaultValue: + WebKitLegacy: +- "PLATFORM(COCOA)": true + default: false + WebKit: +- "PLATFORM(COCOA)": true + default: false + WebCore: +- "PLATFORM(COCOA)": true + default: false + + BlobRegistryTopOriginPartitioningEnabled: +@@ -2257,6 +2255,7 @@ CrossOriginEmbedderPolicyEnabled: WebCore: default: false @@ -2039,7 +1961,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 CrossOriginOpenerPolicyEnabled: type: bool status: stable -@@ -2086,7 +2088,7 @@ CustomPasteboardDataEnabled: +@@ -2297,7 +2296,7 @@ CustomPasteboardDataEnabled: WebKitLegacy: default: false WebKit: @@ -2047,8 +1969,8 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 + "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN)": true default: false - CustomStateSetEnabled: -@@ -2145,6 +2147,7 @@ DOMAudioSessionFullEnabled: + DNSPrefetchingEnabled: +@@ -2342,6 +2341,7 @@ DOMAudioSessionFullEnabled: WebCore: default: false @@ -2056,7 +1978,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 DOMPasteAccessRequestsEnabled: type: bool status: internal -@@ -2156,7 +2159,7 @@ DOMPasteAccessRequestsEnabled: +@@ -2353,7 +2353,7 @@ DOMPasteAccessRequestsEnabled: default: false WebKit: "PLATFORM(IOS) || PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(VISION)": true @@ -2065,7 +1987,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 WebCore: default: false -@@ -2516,7 +2519,7 @@ DirectoryUploadEnabled: +@@ -2691,7 +2691,7 @@ DirectoryUploadEnabled: WebKitLegacy: default: false WebKit: @@ -2074,7 +1996,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 default: false WebCore: default: false -@@ -2939,10 +2942,10 @@ FullScreenEnabled: +@@ -3144,10 +3144,10 @@ FullScreenEnabled: WebKitLegacy: default: false WebKit: @@ -2087,7 +2009,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 default: false sharedPreferenceForWebProcess: true -@@ -3595,6 +3598,7 @@ InspectorAttachmentSide: +@@ -3852,6 +3852,7 @@ InspectorAttachmentSide: WebKit: default: 0 @@ -2095,7 +2017,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 InspectorStartsAttached: type: bool status: embedder -@@ -3602,7 +3606,7 @@ InspectorStartsAttached: +@@ -3859,7 +3860,7 @@ InspectorStartsAttached: exposed: [ WebKit ] defaultValue: WebKit: @@ -2104,7 +2026,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 InspectorWindowFrame: type: String -@@ -3953,9 +3957,10 @@ LayoutViewportHeightExpansionFactor: +@@ -4210,9 +4211,10 @@ LayoutViewportHeightExpansionFactor: WebCore: default: 0 @@ -2116,7 +2038,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 category: html humanReadableName: "Lazy iframe loading" humanReadableDescription: "Enable lazy iframe loading support" -@@ -3963,9 +3968,9 @@ LazyIframeLoadingEnabled: +@@ -4220,9 +4222,9 @@ LazyIframeLoadingEnabled: WebKitLegacy: default: true WebKit: @@ -2128,7 +2050,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 LazyImageLoadingEnabled: type: bool -@@ -5461,7 +5466,7 @@ PermissionsAPIEnabled: +@@ -5781,7 +5783,7 @@ PermissionsAPIEnabled: WebKitLegacy: default: false WebKit: @@ -2137,7 +2059,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 default: false WebCore: default: false -@@ -5524,6 +5529,19 @@ PitchCorrectionAlgorithm: +@@ -5844,6 +5846,19 @@ PitchCorrectionAlgorithm: WebCore: default: MediaPlayerEnums::PitchCorrectionAlgorithm::BestAllAround @@ -2156,8 +2078,8 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 + PointerLockOptionsEnabled: type: bool - status: testable -@@ -6060,7 +6078,7 @@ ScreenOrientationAPIEnabled: + status: stable +@@ -6435,7 +6450,7 @@ ScreenOrientationAPIEnabled: WebKitLegacy: default: false WebKit: @@ -2166,7 +2088,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 WebCore: default: false sharedPreferenceForWebProcess: true -@@ -7389,6 +7407,7 @@ UseCGDisplayListsForDOMRendering: +@@ -7849,6 +7864,7 @@ UseCGDisplayListsForDOMRendering: default: true sharedPreferenceForWebProcess: true @@ -2174,7 +2096,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 UseGPUProcessForCanvasRenderingEnabled: type: bool status: stable -@@ -7401,7 +7420,7 @@ UseGPUProcessForCanvasRenderingEnabled: +@@ -7861,7 +7877,7 @@ UseGPUProcessForCanvasRenderingEnabled: defaultValue: WebKit: "ENABLE(GPU_PROCESS_BY_DEFAULT)": true @@ -2183,15 +2105,15 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 default: false UseGPUProcessForDOMRenderingEnabled: -@@ -7444,6 +7463,7 @@ UseGPUProcessForMediaEnabled: - "ENABLE(GPU_PROCESS_BY_DEFAULT)": true - default: false +@@ -7906,6 +7922,7 @@ UseGPUProcessForMediaEnabled: + sharedPreferenceForWebProcess: true + mediaPlaybackRelated: true +# Playwright: force-disable on Windows. UseGPUProcessForWebGLEnabled: type: bool status: internal -@@ -7455,7 +7475,7 @@ UseGPUProcessForWebGLEnabled: +@@ -7917,7 +7934,7 @@ UseGPUProcessForWebGLEnabled: default: false WebKit: "ENABLE(GPU_PROCESS_BY_DEFAULT) && ENABLE(GPU_PROCESS_WEBGL_BY_DEFAULT)": true @@ -2201,7 +2123,7 @@ index 5b41178d65c94c1b0e1a51e37b21f9b6e827dbdd..716f80a56e5850b26bc7c0d1b2d91d70 WebCore: "ENABLE(GPU_PROCESS_BY_DEFAULT) && ENABLE(GPU_PROCESS_WEBGL_BY_DEFAULT)": true diff --git a/Source/WTF/wtf/PlatformEnable.h b/Source/WTF/wtf/PlatformEnable.h -index 62e05e9711b88f291833ec11fea15caba8d1826c..279be00347cbe501ba09040a511627ed308ecdbd 100644 +index 960b0ee2c7d012bb2ce8f8d22d0cc43176e6285d..9bc7ad7d36dfe90d296143567252bece6f1d56fb 100644 --- a/Source/WTF/wtf/PlatformEnable.h +++ b/Source/WTF/wtf/PlatformEnable.h @@ -409,7 +409,7 @@ @@ -2223,10 +2145,10 @@ index 62e05e9711b88f291833ec11fea15caba8d1826c..279be00347cbe501ba09040a511627ed #if !defined(ENABLE_TOUCH_ACTION_REGIONS) diff --git a/Source/WTF/wtf/PlatformEnableCocoa.h b/Source/WTF/wtf/PlatformEnableCocoa.h -index 256964d0373b4ec43ddccc4c7c50ab9d85259294..c6aff1223553dcdbe2ac5165bc2fd9df763ee191 100644 +index e744e5190e18a46421335614ba7e46abd9321ede..3da0354adfac2df0570273859448435a0ecfc869 100644 --- a/Source/WTF/wtf/PlatformEnableCocoa.h +++ b/Source/WTF/wtf/PlatformEnableCocoa.h -@@ -794,7 +794,7 @@ +@@ -808,7 +808,7 @@ #endif #if !defined(ENABLE_SEC_ITEM_SHIM) @@ -2236,19 +2158,10 @@ index 256964d0373b4ec43ddccc4c7c50ab9d85259294..c6aff1223553dcdbe2ac5165bc2fd9df #if !defined(ENABLE_SERVER_PRECONNECT) diff --git a/Source/WTF/wtf/PlatformHave.h b/Source/WTF/wtf/PlatformHave.h -index fff5b0214d7706179adf40c2701018c260c1c657..fa53df1cd9bbe9348636ce70ede2bcdbfbb2af84 100644 +index 26ff5ab72c69aa405a6834b4ba1a6192f3030f2f..8c60bc012661a840bea7524b454c92c67fdd6919 100644 --- a/Source/WTF/wtf/PlatformHave.h +++ b/Source/WTF/wtf/PlatformHave.h -@@ -433,7 +433,7 @@ - #define HAVE_FOUNDATION_WITH_SAME_SITE_COOKIE_SUPPORT 1 - #endif - --#if PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(HAIKU) || PLATFORM(WPE) -+#if PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(HAIKU) || PLATFORM(WPE) || PLATFORM(WIN) - #define HAVE_OS_DARK_MODE_SUPPORT 1 - #endif - -@@ -1249,7 +1249,8 @@ +@@ -1230,7 +1230,8 @@ #endif #if PLATFORM(MAC) @@ -2258,49 +2171,15 @@ index fff5b0214d7706179adf40c2701018c260c1c657..fa53df1cd9bbe9348636ce70ede2bcdb #endif #if !defined(HAVE_LOCKDOWN_MODE_PDF_ADDITIONS) && \ -diff --git a/Source/WTF/wtf/StdLibExtras.h b/Source/WTF/wtf/StdLibExtras.h -index 134f4922b0bd97ff80caaf7e4ac31b387f1c064f..f132cea6ad3306c5f1bd6252a53bb7b411b0bb54 100644 ---- a/Source/WTF/wtf/StdLibExtras.h -+++ b/Source/WTF/wtf/StdLibExtras.h -@@ -27,6 +27,7 @@ - #pragma once - - #include -+#include - #include - #include - #include -@@ -45,6 +46,22 @@ - - #define SINGLE_ARG(...) __VA_ARGS__ // useful when a macro argument includes a comma - -+// FIXME: Custom implementation not needed once all Linux systems use >libstdc++-10. -+#if !defined(__cpp_lib_bit_cast) || __cpp_lib_bit_cast < 201806L -+namespace std { -+ -+template ::value -+ && std::is_trivially_copyable::value, -+ int>::type = 0> -+inline constexpr T bit_cast(const U &value) { -+ return __builtin_bit_cast(T, value); -+} -+ -+} -+#endif -+ - // Use this macro to declare and define a debug-only global variable that may have a - // non-trivial constructor and destructor. When building with clang, this will suppress - // warnings about global constructors and exit-time destructors. diff --git a/Source/WTF/wtf/unicode/UTF8Conversion.h b/Source/WTF/wtf/unicode/UTF8Conversion.h -index 007b8fe3292f326504013be8198ae020f7aacf35..4439f901b4a9a92d881c7cee24ad9cd28149d276 100644 +index 007b8fe3292f326504013be8198ae020f7aacf35..1c722c473732ffe05fdb61010fa4417e3e399d1f 100644 --- a/Source/WTF/wtf/unicode/UTF8Conversion.h +++ b/Source/WTF/wtf/unicode/UTF8Conversion.h -@@ -27,6 +27,10 @@ +@@ -27,6 +27,11 @@ #include ++// Can be probably removed when we drop Debian 11. +#ifdef Success +#undef Success +#endif @@ -2309,10 +2188,10 @@ index 007b8fe3292f326504013be8198ae020f7aacf35..4439f901b4a9a92d881c7cee24ad9cd2 namespace Unicode { diff --git a/Source/WebCore/DerivedSources.make b/Source/WebCore/DerivedSources.make -index f4df43f3fca6ec439815f3d0f2195abad6b046d6..9706dd76ea82d1dc23226c0ad5fd8cb57ba555b0 100644 +index 18d8c41490fb662d6f5bfb14689469d53244fb82..73ce4360870e6053f79a0c6d6055ffd17da9f7b7 100644 --- a/Source/WebCore/DerivedSources.make +++ b/Source/WebCore/DerivedSources.make -@@ -1191,6 +1191,10 @@ JS_BINDING_IDLS := \ +@@ -1218,6 +1218,10 @@ JS_BINDING_IDLS := \ $(WebCore)/dom/SubscriberCallback.idl \ $(WebCore)/dom/SubscriptionObserver.idl \ $(WebCore)/dom/SubscriptionObserverCallback.idl \ @@ -2323,7 +2202,7 @@ index f4df43f3fca6ec439815f3d0f2195abad6b046d6..9706dd76ea82d1dc23226c0ad5fd8cb5 $(WebCore)/dom/Text.idl \ $(WebCore)/dom/TextDecoder.idl \ $(WebCore)/dom/TextDecoderStream.idl \ -@@ -1783,9 +1787,6 @@ JS_BINDING_IDLS := \ +@@ -1812,9 +1816,6 @@ JS_BINDING_IDLS := \ ADDITIONAL_BINDING_IDLS = \ DocumentTouch.idl \ GestureEvent.idl \ @@ -2334,7 +2213,7 @@ index f4df43f3fca6ec439815f3d0f2195abad6b046d6..9706dd76ea82d1dc23226c0ad5fd8cb5 vpath %.in $(WEBKITADDITIONS_HEADER_SEARCH_PATHS) diff --git a/Source/WebCore/Modules/geolocation/Geolocation.cpp b/Source/WebCore/Modules/geolocation/Geolocation.cpp -index 268f1dfa20097a708f1531975a908fa782b1adb2..5b5eb45dc77aa09be9df39073998eb7a25f44163 100644 +index 90bf15adb6a36e190f68448a125b5446a0674631..d64af222f0c824a7cd719e250c1023071465d24e 100644 --- a/Source/WebCore/Modules/geolocation/Geolocation.cpp +++ b/Source/WebCore/Modules/geolocation/Geolocation.cpp @@ -360,8 +360,9 @@ bool Geolocation::shouldBlockGeolocationRequests() @@ -2349,7 +2228,7 @@ index 268f1dfa20097a708f1531975a908fa782b1adb2..5b5eb45dc77aa09be9df39073998eb7a } diff --git a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm -index 506ebb25fa290f27a75674a6fe5506fc311910d6..07d34c567b42aca08b188243c3f036f64a8da0c4 100644 +index b2b0391c120d527a9ab4bc6daf8bff7ea5d03cf7..d490a95f89f21536fce4f403b86399160abefc23 100644 --- a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm +++ b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm @@ -195,6 +195,7 @@ - (void)sendEndIfNeeded @@ -2385,10 +2264,10 @@ index 506ebb25fa290f27a75674a6fe5506fc311910d6..07d34c567b42aca08b188243c3f036f6 [self sendSpeechEndIfNeeded]; diff --git a/Source/WebCore/PlatformWPE.cmake b/Source/WebCore/PlatformWPE.cmake -index 2aada6f29a04eb3fb0530c47d0fb76f8e3d1bb9f..b936f5862a246c9bf30adbb593c348450b1510ba 100644 +index 7bbcd501126a7b83986f5d1f5a077779441dc1fe..13e68ac853603d8e7da1b42f5c8073ebdab83264 100644 --- a/Source/WebCore/PlatformWPE.cmake +++ b/Source/WebCore/PlatformWPE.cmake -@@ -59,6 +59,8 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS +@@ -60,6 +60,8 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS platform/graphics/gbm/PlatformDisplayGBM.h platform/graphics/libwpe/PlatformDisplayLibWPE.h @@ -2396,15 +2275,15 @@ index 2aada6f29a04eb3fb0530c47d0fb76f8e3d1bb9f..b936f5862a246c9bf30adbb593c34845 + platform/wpe/SelectionData.h ) - set(CSS_VALUE_PLATFORM_DEFINES "HAVE_OS_DARK_MODE_SUPPORT=1") + set(WebCore_USER_AGENT_SCRIPTS_DEPENDENCIES ${WEBCORE_DIR}/platform/wpe/RenderThemeWPE.cpp) diff --git a/Source/WebCore/SourcesCocoa.txt b/Source/WebCore/SourcesCocoa.txt -index 7b59e7fab81dbf2fa1847b40f1aac9437c6af62d..689a87649ab0a1aef273528d41840cca6ced46fe 100644 +index 79893c978df4277dacc7a90f9b0bca73cee6458a..949f92cc972e59af642e548b00d6788568513fa0 100644 --- a/Source/WebCore/SourcesCocoa.txt +++ b/Source/WebCore/SourcesCocoa.txt -@@ -716,3 +716,9 @@ testing/cocoa/WebViewVisualIdentificationOverlay.mm +@@ -728,3 +728,9 @@ testing/cocoa/WebViewVisualIdentificationOverlay.mm platform/graphics/angle/GraphicsContextGLANGLE.cpp @no-unify platform/graphics/cocoa/GraphicsContextGLCocoa.mm @no-unify - platform/graphics/cv/GraphicsContextGLCVCocoa.cpp @no-unify + platform/graphics/cv/GraphicsContextGLCVCocoa.mm @no-unify + +// Playwright begin +JSTouch.cpp @@ -2412,10 +2291,10 @@ index 7b59e7fab81dbf2fa1847b40f1aac9437c6af62d..689a87649ab0a1aef273528d41840cca +JSTouchList.cpp +// Playwright end diff --git a/Source/WebCore/SourcesGTK.txt b/Source/WebCore/SourcesGTK.txt -index cafba5ad19fcce8184f9caeaf50445b3b2065522..75fa95a4f8248ad2d19c2c19dc22166a843f03bb 100644 +index 5838137f6ae130f6ce1e97942078641096d406b6..fcdc7611e36297c1b836ccf44a073781a04809ff 100644 --- a/Source/WebCore/SourcesGTK.txt +++ b/Source/WebCore/SourcesGTK.txt -@@ -112,3 +112,10 @@ platform/unix/LoggingUnix.cpp +@@ -113,3 +113,10 @@ platform/unix/LoggingUnix.cpp platform/unix/SharedMemoryUnix.cpp platform/xdg/MIMETypeRegistryXdg.cpp @@ -2458,12 +2337,12 @@ index 3c68a8ed10cd24cffd26b4b70c3adad8eb6ba91f..b36dee714fdceba5248922bfb6d20469 +JSSpeechSynthesisEventInit.cpp +// Playwright: end. diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj -index 391eed371e8c521098e78df1990dd5dd0a2e1c52..0eb1418a2d334e58faf5011bc65f797b0c8cc322 100644 +index c10b3c0d8d918e2ca0c33e4820b492465ef2fd97..51a6ace79f76cfbee26c96fc75cd9b5c71ba243c 100644 --- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj +++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj -@@ -6224,6 +6224,13 @@ - EDE3A5000C7A430600956A37 /* ColorMac.h in Headers */ = {isa = PBXBuildFile; fileRef = EDE3A4FF0C7A430600956A37 /* ColorMac.h */; settings = {ATTRIBUTES = (Private, ); }; }; +@@ -6358,6 +6358,13 @@ EDEC98030AED7E170059137F /* WebCorePrefix.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEC98020AED7E170059137F /* WebCorePrefix.h */; }; + EE0C7E042CE845CB0043DAF8 /* CSSPositionTryRule.h in Headers */ = {isa = PBXBuildFile; fileRef = EE0C7E002CE845CB0043DAF8 /* CSSPositionTryRule.h */; }; EFCC6C8F20FE914400A2321B /* CanvasActivityRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */; settings = {ATTRIBUTES = (Private, ); }; }; + F050E16823AC9C080011CE47 /* PlatformTouchEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = F050E16623AC9C070011CE47 /* PlatformTouchEvent.h */; settings = {ATTRIBUTES = (Private, ); }; }; + F050E16A23AD660C0011CE47 /* Touch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F050E16923AD660C0011CE47 /* Touch.cpp */; }; @@ -2475,7 +2354,7 @@ index 391eed371e8c521098e78df1990dd5dd0a2e1c52..0eb1418a2d334e58faf5011bc65f797b F12171F616A8CF0B000053CA /* WebVTTElement.h in Headers */ = {isa = PBXBuildFile; fileRef = F12171F416A8BC63000053CA /* WebVTTElement.h */; }; F32BDCD92363AACA0073B6AE /* UserGestureEmulationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = F32BDCD72363AACA0073B6AE /* UserGestureEmulationScope.h */; }; F344C7141125B82C00F26EEE /* InspectorFrontendClient.h in Headers */ = {isa = PBXBuildFile; fileRef = F344C7121125B82C00F26EEE /* InspectorFrontendClient.h */; settings = {ATTRIBUTES = (Private, ); }; }; -@@ -20367,6 +20374,14 @@ +@@ -20908,6 +20915,14 @@ EE7A169F2C607BFA0057B563 /* StartViewTransitionOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StartViewTransitionOptions.h; sourceTree = ""; }; EFB7287B2124C73D005C2558 /* CanvasActivityRecord.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CanvasActivityRecord.cpp; sourceTree = ""; }; EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CanvasActivityRecord.h; sourceTree = ""; }; @@ -2490,7 +2369,7 @@ index 391eed371e8c521098e78df1990dd5dd0a2e1c52..0eb1418a2d334e58faf5011bc65f797b F12171F316A8BC63000053CA /* WebVTTElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebVTTElement.cpp; sourceTree = ""; }; F12171F416A8BC63000053CA /* WebVTTElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVTTElement.h; sourceTree = ""; }; F32BDCD52363AAC90073B6AE /* UserGestureEmulationScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserGestureEmulationScope.cpp; sourceTree = ""; }; -@@ -28052,6 +28067,11 @@ +@@ -28654,6 +28669,11 @@ BC4A5324256055590028C592 /* TextDirectionSubmenuInclusionBehavior.h */, 2D4F96F11A1ECC240098BF88 /* TextIndicator.cpp */, 2D4F96F21A1ECC240098BF88 /* TextIndicator.h */, @@ -2502,16 +2381,16 @@ index 391eed371e8c521098e78df1990dd5dd0a2e1c52..0eb1418a2d334e58faf5011bc65f797b F48570A42644C76D00C05F71 /* TranslationContextMenuInfo.h */, F4E1965F21F26E4E00285078 /* UndoItem.cpp */, 2ECDBAD521D8906300F00ECD /* UndoItem.h */, -@@ -34451,6 +34471,8 @@ +@@ -35537,6 +35557,8 @@ 29E4D8DF16B0940F00C84704 /* PlatformSpeechSynthesizer.h */, 1AD8F81A11CAB9E900E93E54 /* PlatformStrategies.cpp */, 1AD8F81911CAB9E900E93E54 /* PlatformStrategies.h */, + F050E16623AC9C070011CE47 /* PlatformTouchEvent.h */, + F050E17623AD70C40011CE47 /* PlatformTouchPoint.h */, + FE3DC9932D0C063C0021B6FC /* PlatformTZoneImpls.cpp */, 0FD7C21D23CE41E30096D102 /* PlatformWheelEvent.cpp */, 935C476A09AC4D4F00A6AAB4 /* PlatformWheelEvent.h */, - F491A66A2A9FEFA300F96146 /* PlatformWheelEvent.serialization.in */, -@@ -37208,6 +37230,7 @@ +@@ -38326,6 +38348,7 @@ AD6E71AB1668899D00320C13 /* DocumentSharedObjectPool.h */, 6BDB5DC1227BD3B800919770 /* DocumentStorageAccess.cpp */, 6BDB5DC0227BD3B800919770 /* DocumentStorageAccess.h */, @@ -2519,7 +2398,7 @@ index 391eed371e8c521098e78df1990dd5dd0a2e1c52..0eb1418a2d334e58faf5011bc65f797b 7CE7FA5B1EF882300060C9D6 /* DocumentTouch.cpp */, 7CE7FA591EF882300060C9D6 /* DocumentTouch.h */, A8185F3209765765005826D9 /* DocumentType.cpp */, -@@ -41975,6 +41998,8 @@ +@@ -43197,6 +43220,8 @@ F4E90A3C2B52038E002DA469 /* PlatformTextAlternatives.h in Headers */, 0F7D07331884C56C00B4AF86 /* PlatformTextTrack.h in Headers */, 074E82BB18A69F0E007EF54C /* PlatformTimeRanges.h in Headers */, @@ -2528,7 +2407,7 @@ index 391eed371e8c521098e78df1990dd5dd0a2e1c52..0eb1418a2d334e58faf5011bc65f797b CDD08ABD277E542600EA3755 /* PlatformTrackConfiguration.h in Headers */, CD1F9B022700323D00617EB6 /* PlatformVideoColorPrimaries.h in Headers */, CD1F9B01270020B700617EB6 /* PlatformVideoColorSpace.h in Headers */, -@@ -43261,6 +43286,7 @@ +@@ -44527,6 +44552,7 @@ 0F54DD081881D5F5003EEDBB /* Touch.h in Headers */, 71B7EE0D21B5C6870031C1EF /* TouchAction.h in Headers */, 0F54DD091881D5F5003EEDBB /* TouchEvent.h in Headers */, @@ -2536,7 +2415,7 @@ index 391eed371e8c521098e78df1990dd5dd0a2e1c52..0eb1418a2d334e58faf5011bc65f797b 0F54DD0A1881D5F5003EEDBB /* TouchList.h in Headers */, 070334D71459FFD5008D8D45 /* TrackBase.h in Headers */, BE88E0C21715CE2600658D98 /* TrackListBase.h in Headers */, -@@ -44423,6 +44449,8 @@ +@@ -45707,6 +45733,8 @@ 2D22830323A8470700364B7E /* CursorMac.mm in Sources */, 5CBD59592280E926002B22AA /* CustomHeaderFields.cpp in Sources */, 07E4BDBF2A3A5FAB000D5509 /* DictationCaretAnimator.cpp in Sources */, @@ -2545,7 +2424,7 @@ index 391eed371e8c521098e78df1990dd5dd0a2e1c52..0eb1418a2d334e58faf5011bc65f797b 7CE6CBFD187F394900D46BF5 /* FormatConverter.cpp in Sources */, 4667EA3E2968D9DA00BAB1E2 /* GameControllerHapticEffect.mm in Sources */, 46FE73D32968E52000B8064C /* GameControllerHapticEngines.mm in Sources */, -@@ -44511,6 +44539,9 @@ +@@ -45798,6 +45826,9 @@ CE88EE262414467B007F29C2 /* TextAlternativeWithRange.mm in Sources */, BE39137129B267F500FA5D4F /* TextTransformCocoa.cpp in Sources */, 51DF6D800B92A18E00C2DC85 /* ThreadCheck.mm in Sources */, @@ -2556,10 +2435,10 @@ index 391eed371e8c521098e78df1990dd5dd0a2e1c52..0eb1418a2d334e58faf5011bc65f797b 538EC8021F96AF81004D22A8 /* UnifiedSource1.cpp in Sources */, 538EC8051F96AF81004D22A8 /* UnifiedSource2-mm.mm in Sources */, diff --git a/Source/WebCore/accessibility/AccessibilityObject.cpp b/Source/WebCore/accessibility/AccessibilityObject.cpp -index 409ba22d242695a6612a1a2217bb555bd1a382cf..18d6af9e268b353d639aee78642576d6de96fc60 100644 +index f9800e07148d1c3b269a129d90147a1763aa2119..d9e2a2a01162c1b4106b06281dc1c61fbe11ea13 100644 --- a/Source/WebCore/accessibility/AccessibilityObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityObject.cpp -@@ -69,6 +69,7 @@ +@@ -70,6 +70,7 @@ #include "HTMLTableSectionElement.h" #include "HTMLTextAreaElement.h" #include "HitTestResult.h" @@ -2567,7 +2446,7 @@ index 409ba22d242695a6612a1a2217bb555bd1a382cf..18d6af9e268b353d639aee78642576d6 #include "LocalFrame.h" #include "LocalizedStrings.h" #include "MathMLNames.h" -@@ -4018,7 +4019,12 @@ AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const +@@ -3963,7 +3964,12 @@ AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const if (roleValue() == AccessibilityRole::ApplicationDialog) return AccessibilityObjectInclusion::IncludeObject; @@ -2581,33 +2460,11 @@ index 409ba22d242695a6612a1a2217bb555bd1a382cf..18d6af9e268b353d639aee78642576d6 } bool AccessibilityObject::isWithinHiddenWebArea() const -diff --git a/Source/WebCore/accessibility/atspi/AccessibilityObjectTextAtspi.cpp b/Source/WebCore/accessibility/atspi/AccessibilityObjectTextAtspi.cpp -index bdfc31aa68fb0cf0e71351ae86b2af8a903a3c57..fbe06025d4147848cc4c7f3e3bac299da8c98f85 100644 ---- a/Source/WebCore/accessibility/atspi/AccessibilityObjectTextAtspi.cpp -+++ b/Source/WebCore/accessibility/atspi/AccessibilityObjectTextAtspi.cpp -@@ -289,7 +289,7 @@ String AccessibilityObjectAtspi::text() const - if (!value.isNull()) - return value; - -- auto text = m_coreObject->textUnderElement(TextUnderElementMode(TextUnderElementMode::Children::IncludeAllChildren)); -+ auto text = m_coreObject->textUnderElement({ TextUnderElementMode::Children::IncludeAllChildren }); - if (auto* renderer = m_coreObject->renderer()) { - if (is(*renderer) && downcast(*renderer).markerRenderer()) { - if (renderer->style().direction() == TextDirection::LTR) { -@@ -315,7 +315,7 @@ unsigned AccessibilityObject::getLengthForTextRange() const - textLength = downcast(*renderer).text().length(); - - if (!textLength && allowsTextRanges()) -- textLength = textUnderElement(TextUnderElementMode(TextUnderElementMode::Children::IncludeAllChildren)).length(); -+ textLength = textUnderElement({ TextUnderElementMode::Children::IncludeAllChildren }).length(); - - return textLength; - } diff --git a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h -index 479938f501c65222a5820087c578184d64169dec..9bf7df2bc66c77b92edb1f93887922071d539458 100644 +index 9470f5d46c83bb5d0c4f65b75e6a18a7dfaefccb..79eed13cfdf942a04d41032622fad89231a64e9b 100644 --- a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h +++ b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h -@@ -185,6 +185,8 @@ namespace WebCore { +@@ -186,6 +186,8 @@ namespace WebCore { macro(DelayNode) \ macro(DeprecationReportBody) \ macro(DigitalCredential) \ @@ -2617,13 +2474,13 @@ index 479938f501c65222a5820087c578184d64169dec..9bf7df2bc66c77b92edb1f9388792207 macro(DynamicsCompressorNode) \ macro(ElementInternals) \ diff --git a/Source/WebCore/css/query/MediaQueryFeatures.cpp b/Source/WebCore/css/query/MediaQueryFeatures.cpp -index a4f2b2d167f77b19104daa9c56f62ae76485cb1a..c877d2439414452c4dfb79a6881dcf85e1d35fa0 100644 +index 83e2a42d3f09289d61217f63a121611a92aae85d..f4dfda8e9dc1dd9ad221272f09e1bd7f49afa1e0 100644 --- a/Source/WebCore/css/query/MediaQueryFeatures.cpp +++ b/Source/WebCore/css/query/MediaQueryFeatures.cpp -@@ -364,7 +364,11 @@ const FeatureSchema& forcedColors() - static MainThreadNeverDestroyed schema { +@@ -496,7 +496,11 @@ static const IdentifierSchema& forcedColorsFeatureSchema() "forced-colors"_s, FixedVector { CSSValueNone, CSSValueActive }, + OptionSet(), - [](auto&) { + [](auto& context) { + auto* page = context.document->frame()->page(); @@ -2633,7 +2490,7 @@ index a4f2b2d167f77b19104daa9c56f62ae76485cb1a..c877d2439414452c4dfb79a6881dcf85 return MatchingIdentifiers { CSSValueNone }; } }; -@@ -540,6 +544,9 @@ const FeatureSchema& prefersReducedMotion() +@@ -682,6 +686,9 @@ static const IdentifierSchema& prefersReducedMotionFeatureSchema() [](auto& context) { bool userPrefersReducedMotion = [&] { Ref frame = *context.document->frame(); @@ -2644,10 +2501,10 @@ index a4f2b2d167f77b19104daa9c56f62ae76485cb1a..c877d2439414452c4dfb79a6881dcf85 case ForcedAccessibilityValue::On: return true; diff --git a/Source/WebCore/dom/DataTransfer.cpp b/Source/WebCore/dom/DataTransfer.cpp -index 0aec57b302c54f2b02beaeec4a9a6733612212a9..726895552b252b83cdb4f9dd87867a6afc3ed101 100644 +index a3c4d925cded155b15360793d54c57ca54fa2986..80773b244e3ee7aa7e585617c408f7d851154e7f 100644 --- a/Source/WebCore/dom/DataTransfer.cpp +++ b/Source/WebCore/dom/DataTransfer.cpp -@@ -512,6 +512,14 @@ Ref DataTransfer::createForDrag(const Document& document) +@@ -520,6 +520,14 @@ Ref DataTransfer::createForDrag(const Document& document) return adoptRef(*new DataTransfer(StoreMode::ReadWrite, Pasteboard::createForDragAndDrop(PagePasteboardContext::create(document.pageID())), Type::DragAndDropData)); } @@ -2663,10 +2520,10 @@ index 0aec57b302c54f2b02beaeec4a9a6733612212a9..726895552b252b83cdb4f9dd87867a6a { auto dataTransfer = adoptRef(*new DataTransfer(StoreMode::ReadWrite, makeUnique(), Type::DragAndDropData)); diff --git a/Source/WebCore/dom/DataTransfer.h b/Source/WebCore/dom/DataTransfer.h -index 6ca2550bf509381165e5da22cc894ccf6378f45c..535bd1b05e8d90b291235cfc3cb425084455ff26 100644 +index 6327b8ff7709ed58bfd8140e59af87cb3a1f2b51..562812425187e2bae137abb4903a1497d6c4fbab 100644 --- a/Source/WebCore/dom/DataTransfer.h +++ b/Source/WebCore/dom/DataTransfer.h -@@ -91,6 +91,9 @@ public: +@@ -92,6 +92,9 @@ public: #if ENABLE(DRAG_SUPPORT) static Ref createForDrag(const Document&); @@ -2873,7 +2730,7 @@ index 7813532cc52d582c42aebc979a1ecd1137765f08..c01cbd53ad2430a6ffab9a80fc73e74a #endif // USE(LIBWPE) diff --git a/Source/WebCore/html/FileInputType.cpp b/Source/WebCore/html/FileInputType.cpp -index e582d1bc610c7794c4ad181511317d2378b9248b..4c6be4b94913a4649b33f1989def3433455b7109 100644 +index 26e7ca561e3923e2b11da48e777348d3928bff53..a151c289dcd1aef5e0f26faaa7785137296829b8 100644 --- a/Source/WebCore/html/FileInputType.cpp +++ b/Source/WebCore/html/FileInputType.cpp @@ -37,6 +37,7 @@ @@ -2884,7 +2741,7 @@ index e582d1bc610c7794c4ad181511317d2378b9248b..4c6be4b94913a4649b33f1989def3433 #include "LocalFrame.h" #include "LocalizedStrings.h" #include "MIMETypeRegistry.h" -@@ -158,6 +159,11 @@ void FileInputType::handleDOMActivateEvent(Event& event) +@@ -160,6 +161,11 @@ void FileInputType::handleDOMActivateEvent(Event& event) if (input.isDisabledFormControl()) return; @@ -2896,7 +2753,7 @@ index e582d1bc610c7794c4ad181511317d2378b9248b..4c6be4b94913a4649b33f1989def3433 if (!UserGestureIndicator::processingUserGesture()) return; -@@ -346,7 +352,9 @@ void FileInputType::setFiles(RefPtr&& files, RequestIcon shouldRequest +@@ -348,7 +354,9 @@ void FileInputType::setFiles(RefPtr&& files, RequestIcon shouldRequest pathsChanged = true; else { for (unsigned i = 0; i < length; ++i) { @@ -2908,28 +2765,28 @@ index e582d1bc610c7794c4ad181511317d2378b9248b..4c6be4b94913a4649b33f1989def3433 break; } diff --git a/Source/WebCore/inspector/InspectorController.cpp b/Source/WebCore/inspector/InspectorController.cpp -index 9cffa4217cecadfc6813da5fa1a92ec1ca9b8796..32da50b05bb8563e0ded48734451a8e9967e48af 100644 +index ee592715641d111078aec266c9b35c0eea9a6f48..bc403a764837abce3c7771c31c4909b6c0de211e 100644 --- a/Source/WebCore/inspector/InspectorController.cpp +++ b/Source/WebCore/inspector/InspectorController.cpp -@@ -290,6 +290,8 @@ void InspectorController::disconnectFrontend(FrontendChannel& frontendChannel) +@@ -300,6 +300,8 @@ void InspectorController::disconnectFrontend(FrontendChannel& frontendChannel) // Unplug all instrumentations since they aren't needed now. InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get()); + -+ m_pauseWhenShown = false; ++ m_pauseOnStart = PauseCondition::DONT_PAUSE; } m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount()); -@@ -309,6 +311,8 @@ void InspectorController::disconnectAllFrontends() +@@ -319,6 +321,8 @@ void InspectorController::disconnectAllFrontends() // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow(). ASSERT(!m_inspectorFrontendClient); -+ m_pauseWhenShown = false; ++ m_pauseOnStart = PauseCondition::DONT_PAUSE; + if (!m_frontendRouter->hasFrontends()) return; -@@ -397,8 +401,8 @@ void InspectorController::inspect(Node* node) +@@ -402,8 +406,8 @@ void InspectorController::inspect(Node* node) if (!enabled()) return; @@ -2940,25 +2797,35 @@ index 9cffa4217cecadfc6813da5fa1a92ec1ca9b8796..32da50b05bb8563e0ded48734451a8e9 ensureDOMAgent().inspect(node); } -@@ -541,4 +545,24 @@ void InspectorController::didComposite(LocalFrame& frame) +@@ -546,4 +550,34 @@ void InspectorController::didComposite(LocalFrame& frame) InspectorInstrumentation::didComposite(frame); } -+void InspectorController::pauseWhenShown() ++void InspectorController::pauseOnStart(PauseCondition condition) +{ -+ m_pauseWhenShown = true; ++ m_pauseOnStart = condition; +} + +void InspectorController::resumeIfPausedInNewWindow() +{ -+ m_pauseWhenShown = false; ++ m_pauseOnStart = PauseCondition::DONT_PAUSE; +} + -+void InspectorController::didShowNewWindow() ++void InspectorController::didFinishPageCreation() +{ -+ if (!m_pauseWhenShown) -+ return; -+ while (m_pauseWhenShown) { ++ if (m_pauseOnStart == PauseCondition::WHEN_CREATION_FINISHED) ++ runLoopWhilePaused(); ++} ++ ++void InspectorController::didShowPage() ++{ ++ if (m_pauseOnStart == PauseCondition::WHEN_SHOWN) ++ runLoopWhilePaused(); ++} ++ ++void InspectorController::runLoopWhilePaused() ++{ ++ while (m_pauseOnStart != PauseCondition::DONT_PAUSE) { + if (RunLoop::cycle() == RunLoop::CycleResult::Stop) + break; + } @@ -2966,30 +2833,40 @@ index 9cffa4217cecadfc6813da5fa1a92ec1ca9b8796..32da50b05bb8563e0ded48734451a8e9 + } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorController.h b/Source/WebCore/inspector/InspectorController.h -index 41cb9b8d298fbb4cb833346015fbf67c78577dbd..fa1b489eadfc5469bfeec6a35336ffa7fba2c8c1 100644 +index 4f5c1e836876710a554455ec53733f72db63de58..774c4a66af84664a7a83ba0790d147f7bbb4236a 100644 --- a/Source/WebCore/inspector/InspectorController.h +++ b/Source/WebCore/inspector/InspectorController.h -@@ -103,6 +103,10 @@ public: +@@ -106,6 +106,12 @@ public: WEBCORE_EXPORT void willComposite(LocalFrame&); WEBCORE_EXPORT void didComposite(LocalFrame&); -+ WEBCORE_EXPORT void pauseWhenShown(); ++ enum class PauseCondition { DONT_PAUSE, WHEN_SHOWN, WHEN_CREATION_FINISHED }; ++ WEBCORE_EXPORT void pauseOnStart(PauseCondition); + WEBCORE_EXPORT void resumeIfPausedInNewWindow(); -+ WEBCORE_EXPORT void didShowNewWindow(); ++ WEBCORE_EXPORT void didShowPage(); ++ WEBCORE_EXPORT void didFinishPageCreation(); + // Testing support. - WEBCORE_EXPORT bool isUnderTest() const; + bool isUnderTest() const { return m_isUnderTest; } void setIsUnderTest(bool isUnderTest) { m_isUnderTest = isUnderTest; } -@@ -156,6 +160,7 @@ private: +@@ -136,6 +142,7 @@ private: + + PageAgentContext pageAgentContext(); + void createLazyAgents(); ++ void runLoopWhilePaused(); + + WeakRef m_page; + Ref m_instrumentingAgents; +@@ -159,6 +166,7 @@ private: bool m_isAutomaticInspection { false }; bool m_pauseAfterInitialization = { false }; bool m_didCreateLazyAgents { false }; -+ bool m_pauseWhenShown { false }; ++ PauseCondition m_pauseOnStart { PauseCondition::DONT_PAUSE }; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp -index da310c6df500f80d2ae762c890ce9733d892ebd1..50db06b983b2eb4ac89942df94838e009bc82175 100644 +index 98e75f2aec7f7defae1e0260f0a563517a61940e..64e9b1713e600a6aa3f02c2c4c70190240881270 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp @@ -598,6 +598,12 @@ void InspectorInstrumentation::applyUserAgentOverrideImpl(InstrumentingAgents& i @@ -3078,7 +2955,7 @@ index da310c6df500f80d2ae762c890ce9733d892ebd1..50db06b983b2eb4ac89942df94838e00 + inspectorPageAgent->didNavigateWithinPage(frame); +} + - #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) + #if ENABLE(DARK_MODE_CSS) void InspectorInstrumentation::defaultAppearanceDidChangeImpl(InstrumentingAgents& instrumentingAgents) { @@ -915,6 +924,12 @@ void InspectorInstrumentation::interceptResponseImpl(InstrumentingAgents& instru @@ -3159,7 +3036,7 @@ index da310c6df500f80d2ae762c890ce9733d892ebd1..50db06b983b2eb4ac89942df94838e00 { // Using RefPtr makes us hit the m_inRemovedLastRefFunction assert. diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h -index 156e222e4383bee7448347d84cb052b0d9b9ae70..9bce3a168c314fc34043578c248d69cb89b48426 100644 +index 81d38dfe2e63476b86b87fccc3544090454ae683..7dfb4d6ed4a795bae882e70c80821befb7818c5b 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.h +++ b/Source/WebCore/inspector/InspectorInstrumentation.h @@ -31,6 +31,7 @@ @@ -3215,7 +3092,7 @@ index 156e222e4383bee7448347d84cb052b0d9b9ae70..9bce3a168c314fc34043578c248d69cb static void frameClearedScheduledNavigation(Frame&); static void accessibilitySettingsDidChange(Page&); + static void didNavigateWithinPage(LocalFrame&); - #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) + #if ENABLE(DARK_MODE_CSS) static void defaultAppearanceDidChange(Page&); #endif @@ -248,6 +253,7 @@ public: @@ -3285,7 +3162,7 @@ index 156e222e4383bee7448347d84cb052b0d9b9ae70..9bce3a168c314fc34043578c248d69cb static void frameClearedScheduledNavigationImpl(InstrumentingAgents&, Frame&); static void accessibilitySettingsDidChangeImpl(InstrumentingAgents&); + static void didNavigateWithinPageImpl(InstrumentingAgents&, LocalFrame&); - #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) + #if ENABLE(DARK_MODE_CSS) static void defaultAppearanceDidChangeImpl(InstrumentingAgents&); #endif @@ -463,6 +480,7 @@ private: @@ -3384,7 +3261,7 @@ index 156e222e4383bee7448347d84cb052b0d9b9ae70..9bce3a168c314fc34043578c248d69cb + didNavigateWithinPageImpl(*agents, frame); +} + - #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) + #if ENABLE(DARK_MODE_CSS) inline void InspectorInstrumentation::defaultAppearanceDidChange(Page& page) { @@ -1362,6 +1401,13 @@ inline void InspectorInstrumentation::interceptResponse(const LocalFrame& frame, @@ -3509,7 +3386,7 @@ index c028341e84e59a6b1b16107fd74feb21f70b12ab..d385418ac34e8f315f201801a2c65226 + } diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp -index f2d47e0b0a15f48600bb6edd10430073ea60d9ee..20ee16a8c858599340ae33869baa188f9b17ae3f 100644 +index f671c06ea5c75e6f4df338ac6c404533a04a3cfd..0d6e106c19063b0ffaeca1cc6830da0729510cbf 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp @@ -55,6 +55,7 @@ @@ -3570,7 +3447,7 @@ index f2d47e0b0a15f48600bb6edd10430073ea60d9ee..20ee16a8c858599340ae33869baa188f } static Color parseOptionalConfigColor(const String& fieldName, JSON::Object& configObject) -@@ -196,6 +205,20 @@ static bool parseQuad(Ref&& quadArray, FloatQuad* quad) +@@ -195,6 +204,20 @@ static bool parseQuad(Ref&& quadArray, FloatQuad* quad) return true; } @@ -3588,10 +3465,10 @@ index f2d47e0b0a15f48600bb6edd10430073ea60d9ee..20ee16a8c858599340ae33869baa188f + renderer->absoluteQuads(quads); +} + - class RevalidateStyleAttributeTask { - WTF_MAKE_TZONE_ALLOCATED_INLINE(RevalidateStyleAttributeTask); - public: -@@ -470,6 +493,20 @@ Node* InspectorDOMAgent::assertNode(Inspector::Protocol::ErrorString& errorStrin + class RevalidateStyleAttributeTask final : public CanMakeCheckedPtr { + WTF_MAKE_TZONE_ALLOCATED(RevalidateStyleAttributeTask); + WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(RevalidateStyleAttributeTask); +@@ -475,6 +498,20 @@ Node* InspectorDOMAgent::assertNode(Inspector::Protocol::ErrorString& errorStrin return node.get(); } @@ -3612,7 +3489,7 @@ index f2d47e0b0a15f48600bb6edd10430073ea60d9ee..20ee16a8c858599340ae33869baa188f Document* InspectorDOMAgent::assertDocument(Inspector::Protocol::ErrorString& errorString, Inspector::Protocol::DOM::NodeId nodeId) { RefPtr node = assertNode(errorString, nodeId); -@@ -1544,16 +1581,7 @@ Inspector::Protocol::ErrorStringOr InspectorDOMAgent::highlightNode(std::o +@@ -1549,16 +1586,7 @@ Inspector::Protocol::ErrorStringOr InspectorDOMAgent::highlightNode(std::o Inspector::Protocol::ErrorStringOr InspectorDOMAgent::highlightNode(std::optional&& nodeId, const Inspector::Protocol::Runtime::RemoteObjectId& objectId, Ref&& highlightInspectorObject, RefPtr&& gridOverlayInspectorObject, RefPtr&& flexOverlayInspectorObject, std::optional&& showRulers) { Inspector::Protocol::ErrorString errorString; @@ -3630,7 +3507,7 @@ index f2d47e0b0a15f48600bb6edd10430073ea60d9ee..20ee16a8c858599340ae33869baa188f if (!node) return makeUnexpected(errorString); -@@ -1808,15 +1836,155 @@ Inspector::Protocol::ErrorStringOr InspectorDOMAgent::setInspectedNode(Ins +@@ -1813,15 +1841,155 @@ Inspector::Protocol::ErrorStringOr InspectorDOMAgent::setInspectedNode(Ins return { }; } @@ -3789,7 +3666,7 @@ index f2d47e0b0a15f48600bb6edd10430073ea60d9ee..20ee16a8c858599340ae33869baa188f if (!object) return makeUnexpected("Missing injected script for given nodeId"_s); -@@ -3082,7 +3250,7 @@ Inspector::Protocol::ErrorStringOr InspectorDO +@@ -3087,7 +3255,7 @@ Inspector::Protocol::ErrorStringOr InspectorDO return makeUnexpected("Missing node for given path"_s); } @@ -3798,7 +3675,7 @@ index f2d47e0b0a15f48600bb6edd10430073ea60d9ee..20ee16a8c858599340ae33869baa188f { Document* document = &node->document(); if (auto* templateHost = document->templateDocumentHost()) -@@ -3091,12 +3259,18 @@ RefPtr InspectorDOMAgent::resolveNod +@@ -3096,12 +3264,18 @@ RefPtr InspectorDOMAgent::resolveNod if (!frame) return nullptr; @@ -3820,7 +3697,7 @@ index f2d47e0b0a15f48600bb6edd10430073ea60d9ee..20ee16a8c858599340ae33869baa188f } Node* InspectorDOMAgent::scriptValueAsNode(JSC::JSValue value) -@@ -3204,4 +3378,89 @@ Inspector::Protocol::ErrorStringOr> In +@@ -3209,4 +3383,89 @@ Inspector::Protocol::ErrorStringOr> In #endif } @@ -3911,10 +3788,10 @@ index f2d47e0b0a15f48600bb6edd10430073ea60d9ee..20ee16a8c858599340ae33869baa188f + } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.h b/Source/WebCore/inspector/agents/InspectorDOMAgent.h -index 978176d20859bf70ce8e44acbb052ceca9463b06..44fd236a64a05290c9f3cbf0b17398f74c711d3b 100644 +index ab0499c5e381855f55fa89227f4da05c7bcf40b1..e506a903ba60173b47135d5b18cfa0d3cdd8783e 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.h +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.h -@@ -58,6 +58,7 @@ namespace WebCore { +@@ -59,6 +59,7 @@ namespace WebCore { class AXCoreObject; class CharacterData; @@ -3922,7 +3799,7 @@ index 978176d20859bf70ce8e44acbb052ceca9463b06..44fd236a64a05290c9f3cbf0b17398f7 class DOMEditor; class Document; class Element; -@@ -92,6 +93,7 @@ public: +@@ -94,6 +95,7 @@ public: static String toErrorString(Exception&&); static String documentURLString(Document*); @@ -3930,7 +3807,7 @@ index 978176d20859bf70ce8e44acbb052ceca9463b06..44fd236a64a05290c9f3cbf0b17398f7 // We represent embedded doms as a part of the same hierarchy. Hence we treat children of frame owners differently. // We also skip whitespace text nodes conditionally. Following methods encapsulate these specifics. -@@ -135,7 +137,7 @@ public: +@@ -137,7 +139,7 @@ public: Inspector::Protocol::ErrorStringOr> performSearch(const String& query, RefPtr&& nodeIds, std::optional&& caseSensitive); Inspector::Protocol::ErrorStringOr>> getSearchResults(const String& searchId, int fromIndex, int toIndex); Inspector::Protocol::ErrorStringOr discardSearchResults(const String& searchId); @@ -3939,7 +3816,7 @@ index 978176d20859bf70ce8e44acbb052ceca9463b06..44fd236a64a05290c9f3cbf0b17398f7 Inspector::Protocol::ErrorStringOr>> getAttributes(Inspector::Protocol::DOM::NodeId); #if PLATFORM(IOS_FAMILY) Inspector::Protocol::ErrorStringOr setInspectModeEnabled(bool, RefPtr&& highlightConfig, RefPtr&& gridOverlayConfig, RefPtr&& flexOverlayConfig); -@@ -172,6 +174,10 @@ public: +@@ -174,6 +176,10 @@ public: Inspector::Protocol::ErrorStringOr setInspectedNode(Inspector::Protocol::DOM::NodeId); Inspector::Protocol::ErrorStringOr setAllowEditingUserAgentShadowTrees(bool); Inspector::Protocol::ErrorStringOr> getMediaStats(Inspector::Protocol::DOM::NodeId); @@ -3950,7 +3827,7 @@ index 978176d20859bf70ce8e44acbb052ceca9463b06..44fd236a64a05290c9f3cbf0b17398f7 // InspectorInstrumentation Inspector::Protocol::DOM::NodeId identifierForNode(Node&); -@@ -213,7 +219,7 @@ public: +@@ -215,7 +221,7 @@ public: Node* nodeForId(Inspector::Protocol::DOM::NodeId); Inspector::Protocol::DOM::NodeId boundNodeId(const Node*); @@ -3959,7 +3836,7 @@ index 978176d20859bf70ce8e44acbb052ceca9463b06..44fd236a64a05290c9f3cbf0b17398f7 bool handleMousePress(); void mouseDidMoveOverElement(const HitTestResult&, OptionSet); void inspect(Node*); -@@ -225,12 +231,15 @@ public: +@@ -227,12 +233,15 @@ public: void reset(); Node* assertNode(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId); @@ -3975,7 +3852,7 @@ index 978176d20859bf70ce8e44acbb052ceca9463b06..44fd236a64a05290c9f3cbf0b17398f7 private: #if ENABLE(VIDEO) void mediaMetricsTimerFired(); -@@ -260,7 +269,6 @@ private: +@@ -262,7 +271,6 @@ private: void processAccessibilityChildren(AXCoreObject&, JSON::ArrayOf&); Node* nodeForPath(const String& path); @@ -3984,7 +3861,7 @@ index 978176d20859bf70ce8e44acbb052ceca9463b06..44fd236a64a05290c9f3cbf0b17398f7 void discardBindings(); diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp -index adbedee377dad747f03b98cfdcf719b4283e51b2..475365f50feeb28354fa3e86ff847a6fd65c8a21 100644 +index 3c4c9d809004f683d1248be257980bbbc522d132..cfa772a5caa5f0a7db07dc853036e21db2bb9814 100644 --- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp @@ -59,6 +59,7 @@ @@ -4140,13 +4017,14 @@ index eda400879afb10b687fcbb317c9fdbb3be9c94cd..f3a382c44b53e6b1507fc046e22bff68 } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp -index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb98c6cc8fb 100644 +index 8cd529462736f59fa7b24bdb887faf61e88036dd..25df35396b5fd35a9431e8d47168e3527edffdf2 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp -@@ -32,19 +32,26 @@ +@@ -32,19 +32,27 @@ #include "config.h" #include "InspectorPageAgent.h" ++#include "AXCoreObject.h" +#include "AXObjectCache.h" +#include "BackForwardController.h" #include "CachedResource.h" @@ -4170,11 +4048,9 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 #include "HTMLNames.h" #include "ImageBuffer.h" #include "InspectorClient.h" -@@ -55,10 +62,13 @@ - #include "LocalFrame.h" - #include "LocalFrameView.h" +@@ -57,8 +65,12 @@ #include "MIMETypeRegistry.h" --#include "MemoryCache.h" + #include "MemoryCache.h" #include "Page.h" +#include "PageRuntimeAgent.h" +#include "PlatformScreen.h" @@ -4185,7 +4061,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 #include "ScriptController.h" #include "ScriptSourceCode.h" #include "SecurityOrigin.h" -@@ -66,15 +76,23 @@ +@@ -67,14 +79,23 @@ #include "StyleScope.h" #include "Theme.h" #include @@ -4205,24 +4081,23 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 #include #include #include --#include +#include + #include #if ENABLE(APPLICATION_MANIFEST) - #include "CachedApplicationManifest.h" -@@ -95,6 +113,11 @@ using namespace Inspector; +@@ -96,6 +117,11 @@ using namespace Inspector; WTF_MAKE_TZONE_ALLOCATED_IMPL(InspectorPageAgent); -+static HashMap>& createdUserWorlds() { -+ static NeverDestroyed>> nameToWorld; ++static UncheckedKeyHashMap>& createdUserWorlds() { ++ static NeverDestroyed>> nameToWorld; + return nameToWorld; +} + static bool decodeBuffer(std::span buffer, const String& textEncodingName, String* result) { if (buffer.data()) { -@@ -341,6 +364,7 @@ InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClien +@@ -348,6 +374,7 @@ InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClien , m_frontendDispatcher(makeUnique(context.frontendRouter)) , m_backendDispatcher(Inspector::PageBackendDispatcher::create(context.backendDispatcher, this)) , m_inspectedPage(context.inspectedPage) @@ -4230,7 +4105,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 , m_client(client) , m_overlay(overlay) { -@@ -370,12 +394,20 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::enable() +@@ -377,12 +404,20 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::enable() defaultUserPreferencesDidChange(); @@ -4251,7 +4126,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 setShowPaintRects(false); #if !PLATFORM(IOS_FAMILY) -@@ -427,6 +459,22 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::reload(std::optiona +@@ -435,6 +470,22 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::reload(std::optiona return { }; } @@ -4273,8 +4148,8 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 + Inspector::Protocol::ErrorStringOr InspectorPageAgent::navigate(const String& url) { - auto* localMainFrame = dynamicDowncast(m_inspectedPage.mainFrame()); -@@ -450,6 +498,13 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideUserAgent(c + RefPtr localMainFrame = m_inspectedPage.localMainFrame(); +@@ -461,6 +512,13 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideUserAgent(c return { }; } @@ -4288,7 +4163,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Inspector::Protocol::Page::Setting setting, std::optional&& value) { auto& inspectedPageSettings = m_inspectedPage.settings(); -@@ -463,6 +518,12 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins +@@ -474,6 +532,12 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins inspectedPageSettings.setAuthorAndUserStylesEnabledInspectorOverride(value); return { }; @@ -4301,8 +4176,8 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 case Inspector::Protocol::Page::Setting::ICECandidateFilteringEnabled: inspectedPageSettings.setICECandidateFilteringEnabledInspectorOverride(value); return { }; -@@ -488,6 +549,38 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins - inspectedPageSettings.setNeedsSiteSpecificQuirksInspectorOverride(value); +@@ -500,6 +564,45 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins + m_client->setDeveloperPreferenceOverride(InspectorClient::DeveloperPreference::NeedsSiteSpecificQuirks, value); return { }; +#if ENABLE(NOTIFICATIONS) @@ -4331,6 +4206,13 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 +#endif + return { }; + ++ case Protocol::Page::Setting::FixedBackgroundsPaintRelativeToDocument: ++ // Enable this setting similar to iOS to ensure scrolling works with ++ // `background-attachment: fixed`. ++ // See https://github.com/microsoft/playwright/issues/31551. ++ inspectedPageSettings.setFixedBackgroundsPaintRelativeToDocument(value.value_or(false)); ++ return { }; ++ +#if ENABLE(POINTER_LOCK) + case Protocol::Page::Setting::PointerLockEnabled: + inspectedPageSettings.setPointerLockEnabled(value.value_or(false)); @@ -4340,7 +4222,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 case Inspector::Protocol::Page::Setting::ScriptEnabled: inspectedPageSettings.setScriptEnabledInspectorOverride(value); return { }; -@@ -500,6 +593,12 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins +@@ -512,6 +615,12 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins inspectedPageSettings.setShowRepaintCounterInspectorOverride(value); return { }; @@ -4353,7 +4235,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 case Inspector::Protocol::Page::Setting::WebSecurityEnabled: inspectedPageSettings.setWebSecurityEnabledInspectorOverride(value); return { }; -@@ -900,15 +999,16 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::setShowPaintRects(b +@@ -919,15 +1028,16 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::setShowPaintRects(b return { }; } @@ -4375,7 +4257,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 } void InspectorPageAgent::frameNavigated(LocalFrame& frame) -@@ -916,13 +1016,38 @@ void InspectorPageAgent::frameNavigated(LocalFrame& frame) +@@ -935,13 +1045,38 @@ void InspectorPageAgent::frameNavigated(LocalFrame& frame) m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame)); } @@ -4395,7 +4277,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 + + String processIDString = frameID.left(dotPos); + uint64_t pid = strtoull(processIDString.ascii().data(), 0, 10); -+ auto processID = LegacyNullableObjectIdentifier(pid); ++ auto processID = ObjectIdentifier(pid); + String frameIDString = frameID.substring(dotPos + 1); + uint64_t frameIDNumber = strtoull(frameIDString.ascii().data(), 0, 10); + return WebCore::FrameIdentifier { @@ -4417,7 +4299,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 } Frame* InspectorPageAgent::frameForId(const Inspector::Protocol::Network::FrameId& frameId) -@@ -934,20 +1059,21 @@ String InspectorPageAgent::frameId(Frame* frame) +@@ -953,20 +1088,21 @@ String InspectorPageAgent::frameId(Frame* frame) { if (!frame) return emptyString(); @@ -4447,7 +4329,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 } LocalFrame* InspectorPageAgent::assertFrame(Inspector::Protocol::ErrorString& errorString, const Inspector::Protocol::Network::FrameId& frameId) -@@ -958,11 +1084,6 @@ LocalFrame* InspectorPageAgent::assertFrame(Inspector::Protocol::ErrorString& er +@@ -977,11 +1113,6 @@ LocalFrame* InspectorPageAgent::assertFrame(Inspector::Protocol::ErrorString& er return frame; } @@ -4459,7 +4341,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 void InspectorPageAgent::frameStartedLoading(LocalFrame& frame) { m_frontendDispatcher->frameStartedLoading(frameId(&frame)); -@@ -973,9 +1094,9 @@ void InspectorPageAgent::frameStoppedLoading(LocalFrame& frame) +@@ -992,9 +1123,9 @@ void InspectorPageAgent::frameStoppedLoading(LocalFrame& frame) m_frontendDispatcher->frameStoppedLoading(frameId(&frame)); } @@ -4471,7 +4353,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 } void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame) -@@ -1022,6 +1143,12 @@ void InspectorPageAgent::defaultUserPreferencesDidChange() +@@ -1041,6 +1172,12 @@ void InspectorPageAgent::defaultUserPreferencesDidChange() m_frontendDispatcher->defaultUserPreferencesDidChange(WTFMove(defaultUserPreferences)); } @@ -4481,10 +4363,10 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 + m_frontendDispatcher->navigatedWithinDocument(frameId(&frame), url); +} + - #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) + #if ENABLE(DARK_MODE_CSS) void InspectorPageAgent::defaultAppearanceDidChange() { -@@ -1035,6 +1162,9 @@ void InspectorPageAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapp +@@ -1054,6 +1191,9 @@ void InspectorPageAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapp return; if (m_bootstrapScript.isEmpty()) @@ -4494,8 +4376,8 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 return; frame.script().evaluateIgnoringException(ScriptSourceCode(m_bootstrapScript, JSC::SourceTaintedOrigin::Untainted, URL { "web-inspector://bootstrap.js"_str })); -@@ -1082,6 +1212,51 @@ void InspectorPageAgent::didRecalculateStyle() - m_overlay->update(); +@@ -1101,6 +1241,51 @@ void InspectorPageAgent::didRecalculateStyle() + protectedOverlay()->update(); } +void InspectorPageAgent::runOpenPanel(HTMLInputElement* element, bool* intercept) @@ -4546,7 +4428,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 Ref InspectorPageAgent::buildObjectForFrame(LocalFrame* frame) { ASSERT_ARG(frame, frame); -@@ -1179,6 +1354,12 @@ void InspectorPageAgent::applyUserAgentOverride(String& userAgent) +@@ -1194,6 +1379,12 @@ void InspectorPageAgent::applyUserAgentOverride(String& userAgent) userAgent = m_userAgentOverride; } @@ -4559,7 +4441,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 void InspectorPageAgent::applyEmulatedMedia(AtomString& media) { if (!m_emulatedMedia.isEmpty()) -@@ -1206,11 +1387,13 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::snapshotNode(Insp +@@ -1221,11 +1412,13 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::snapshotNode(Insp return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes); } @@ -4573,8 +4455,8 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 + options.flags.add(SnapshotFlags::OmitDeviceScaleFactor); IntRect rectangle(x, y, width, height); - auto* localMainFrame = dynamicDowncast(m_inspectedPage.mainFrame()); -@@ -1224,6 +1407,43 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::snapshotRect(int + RefPtr localMainFrame = m_inspectedPage.localMainFrame(); +@@ -1239,6 +1432,43 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::snapshotRect(int return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes); } @@ -4610,7 +4492,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 +Protocol::ErrorStringOr InspectorPageAgent::setTouchEmulationEnabled(bool enabled) +{ + setScreenHasTouchDeviceOverride(enabled); -+ m_inspectedPage.settings().setTouchEventsEnabled(enabled); ++ m_inspectedPage.settings().setTouchEventDOMAttributesEnabled(enabled); + return { }; +} + @@ -4618,7 +4500,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 #if ENABLE(WEB_ARCHIVE) && USE(CF) Inspector::Protocol::ErrorStringOr InspectorPageAgent::archive() { -@@ -1240,7 +1460,6 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::archive() +@@ -1255,7 +1485,6 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::archive() } #endif @@ -4626,7 +4508,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 Inspector::Protocol::ErrorStringOr InspectorPageAgent::setScreenSizeOverride(std::optional&& width, std::optional&& height) { if (width.has_value() != height.has_value()) -@@ -1258,6 +1477,508 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::setScreenSizeOverri +@@ -1273,6 +1502,498 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::setScreenSizeOverri localMainFrame->setOverrideScreenSize(FloatSize(width.value_or(0), height.value_or(0))); return { }; } @@ -4759,8 +4641,6 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 + return "ImageMap"_s; + case AccessibilityRole::ImageMapLink: + return "ImageMapLink"_s; -+ case AccessibilityRole::Incrementor: -+ return "Incrementor"_s; + case AccessibilityRole::Insertion: + return "Insertion"_s; + case AccessibilityRole::Label: @@ -4805,8 +4685,6 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 + return "Menu"_s; + case AccessibilityRole::MenuBar: + return "MenuBar"_s; -+ case AccessibilityRole::MenuButton: -+ return "MenuButton"_s; + case AccessibilityRole::MenuItem: + return "MenuItem"_s; + case AccessibilityRole::MenuItemCheckbox: @@ -4843,14 +4721,8 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 + return "Row"_s; + case AccessibilityRole::RowGroup: + return "RowGroup"_s; -+ case AccessibilityRole::RubyBase: -+ return "RubyBase"_s; -+ case AccessibilityRole::RubyBlock: -+ return "RubyBlock"_s; + case AccessibilityRole::RubyInline: + return "RubyInline"_s; -+ case AccessibilityRole::RubyRun: -+ return "RubyRun"_s; + case AccessibilityRole::RubyText: + return "RubyText"_s; + case AccessibilityRole::ScrollArea: @@ -4939,7 +4811,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 + return "Unknown"_s; +} + -+static Ref snapshotForAXObject(RefPtr axObject, Node* nodeToFind) ++static Ref snapshotForAXObject(WTF::RefPtr axObject, Node* nodeToFind) +{ + auto axNode = Inspector::Protocol::Page::AXNode::create() + .setRole(roleFromObject(axObject)) @@ -5029,7 +4901,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 + if (!axObject->children().isEmpty()) { + Ref> children = JSON::ArrayOf::create(); + for (auto& childObject : axObject->children()) -+ children->addItem(snapshotForAXObject(childObject, nodeToFind)); ++ children->addItem(snapshotForAXObject(childObject.ptr(), nodeToFind)); + axNode->setChildren(WTFMove(children)); + } + return axNode; @@ -5122,7 +4994,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 + +Protocol::ErrorStringOr InspectorPageAgent::crash() +{ -+ CRASH(); ++ WTFCrash(); + return { }; +} + @@ -5137,7 +5009,7 @@ index 85f9e83e59abc5a1089a4f2b56f0dab99437d948..22843714b46b158faa929be669638cb9 } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.h b/Source/WebCore/inspector/agents/InspectorPageAgent.h -index 4f78a536c4030b8065d189aacc378d56d3451198..8ffac8bf16c00543ab8cf410e603b06204357714 100644 +index c72739aab6ddb20cac65cbe82a14a38d860ae0bd..502b0acd85fe625c13b45f287e38493a772fac1b 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.h +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.h @@ -32,8 +32,10 @@ @@ -5151,8 +5023,8 @@ index 4f78a536c4030b8065d189aacc378d56d3451198..8ffac8bf16c00543ab8cf410e603b062 #include #include #include -@@ -42,11 +44,16 @@ - #include +@@ -43,11 +45,16 @@ + #include #include +namespace Inspector { @@ -5168,7 +5040,7 @@ index 4f78a536c4030b8065d189aacc378d56d3451198..8ffac8bf16c00543ab8cf410e603b062 class InspectorClient; class InspectorOverlay; class LocalFrame; -@@ -79,6 +86,8 @@ public: +@@ -80,6 +87,8 @@ public: OtherResource, }; @@ -5177,7 +5049,7 @@ index 4f78a536c4030b8065d189aacc378d56d3451198..8ffac8bf16c00543ab8cf410e603b062 static bool sharedBufferContent(RefPtr&&, const String& textEncodingName, bool withBase64Encode, String* result); static Vector cachedResourcesForFrame(LocalFrame*); static void resourceContent(Inspector::Protocol::ErrorString&, LocalFrame*, const URL&, String* result, bool* base64Encoded); -@@ -99,8 +108,11 @@ public: +@@ -100,8 +109,11 @@ public: Inspector::Protocol::ErrorStringOr enable(); Inspector::Protocol::ErrorStringOr disable(); Inspector::Protocol::ErrorStringOr reload(std::optional&& ignoreCache, std::optional&& revalidateAllResources); @@ -5189,7 +5061,7 @@ index 4f78a536c4030b8065d189aacc378d56d3451198..8ffac8bf16c00543ab8cf410e603b062 Inspector::Protocol::ErrorStringOr overrideSetting(Inspector::Protocol::Page::Setting, std::optional&& value); Inspector::Protocol::ErrorStringOr overrideUserPreference(Inspector::Protocol::Page::UserPreferenceName, std::optional&&); Inspector::Protocol::ErrorStringOr>> getCookies(); -@@ -116,45 +128,65 @@ public: +@@ -117,45 +129,65 @@ public: #endif Inspector::Protocol::ErrorStringOr setShowPaintRects(bool); Inspector::Protocol::ErrorStringOr setEmulatedMedia(const String&); @@ -5231,7 +5103,7 @@ index 4f78a536c4030b8065d189aacc378d56d3451198..8ffac8bf16c00543ab8cf410e603b062 void accessibilitySettingsDidChange(); void defaultUserPreferencesDidChange(); + void didNavigateWithinPage(LocalFrame&); - #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) + #if ENABLE(DARK_MODE_CSS) void defaultAppearanceDidChange(); #endif void applyUserAgentOverride(String&); @@ -5260,19 +5132,19 @@ index 4f78a536c4030b8065d189aacc378d56d3451198..8ffac8bf16c00543ab8cf410e603b062 double timestamp(); + void ensureUserWorldsExistInAllFrames(const Vector&); - static bool mainResourceContent(LocalFrame*, bool withBase64Encode, String* result); - static bool dataContent(std::span data, const String& textEncodingName, bool withBase64Encode, String* result); -@@ -170,17 +202,21 @@ private: + Ref protectedOverlay() const; + +@@ -173,17 +205,22 @@ private: RefPtr m_backendDispatcher; Page& m_inspectedPage; + Inspector::InjectedScriptManager& m_injectedScriptManager; InspectorClient* m_client { nullptr }; - InspectorOverlay* m_overlay { nullptr }; + WeakRef m_overlay; - WeakHashMap m_frameToIdentifier; MemoryCompactRobinHoodHashMap> m_identifierToFrame; -- HashMap m_loaderToIdentifier; + HashMap m_loaderToIdentifier; String m_userAgentOverride; + String m_platformOverride; AtomString m_emulatedMedia; @@ -5287,7 +5159,7 @@ index 4f78a536c4030b8065d189aacc378d56d3451198..8ffac8bf16c00543ab8cf410e603b062 } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp -index 009092f4dd46f22aef63ffa0a9758884859e7385..545da93ce753072c18279c67b1589aefcc7e0b8d 100644 +index fe77f9c4f424a9bbf5cdd6c0721a368767aa374c..0a76877d74a791cd1659c173221ee18cf7bb9fb7 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp @@ -34,6 +34,7 @@ @@ -5306,7 +5178,7 @@ index 009092f4dd46f22aef63ffa0a9758884859e7385..545da93ce753072c18279c67b1589aef #include "SecurityOrigin.h" #include "UserGestureEmulationScope.h" #include -@@ -88,13 +90,73 @@ Inspector::Protocol::ErrorStringOr PageRuntimeAgent::disable() +@@ -88,13 +90,74 @@ Inspector::Protocol::ErrorStringOr PageRuntimeAgent::disable() { m_instrumentingAgents.setEnabledPageRuntimeAgent(nullptr); @@ -5353,6 +5225,7 @@ index 009092f4dd46f22aef63ffa0a9758884859e7385..545da93ce753072c18279c67b1589aef +{ + JSC::JSGlobalObject* globalObject = frame.script().globalObject(mainThreadNormalWorld()); + auto& vm = globalObject->vm(); ++ JSC::JSLockHolder lock(vm); + globalObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, name), 1, bindingCallback, JSC::ImplementationVisibility::Public, JSC::NoIntrinsic, JSC::attributesForStructure(static_cast(JSC::PropertyAttribute::Function))); +} + @@ -5380,7 +5253,7 @@ index 009092f4dd46f22aef63ffa0a9758884859e7385..545da93ce753072c18279c67b1589aef } void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapperWorld& world) -@@ -103,7 +165,26 @@ void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapper +@@ -103,7 +166,26 @@ void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapper if (!pageAgent) return; @@ -5407,7 +5280,7 @@ index 009092f4dd46f22aef63ffa0a9758884859e7385..545da93ce753072c18279c67b1589aef } InjectedScript PageRuntimeAgent::injectedScriptForEval(Inspector::Protocol::ErrorString& errorString, std::optional&& executionContextId) -@@ -142,9 +223,6 @@ void PageRuntimeAgent::reportExecutionContextCreation() +@@ -142,9 +224,6 @@ void PageRuntimeAgent::reportExecutionContextCreation() return; m_inspectedPage.forEachLocalFrame([&](LocalFrame& frame) { @@ -5452,18 +5325,18 @@ index b70ca7636463b9199bcbb21bfea055870ba33b34..25fdc23bfb71985fe1af04bddc360d11 } // namespace WebCore diff --git a/Source/WebCore/loader/CookieJar.h b/Source/WebCore/loader/CookieJar.h -index 2b0060e70df5765f37426eb32c98540dd3a51356..e4682fb4fad491c906ea4b5b1e98c0631e387a7b 100644 +index 8fb27c1045b8073d1487d5b61ccdec23a395bfd1..5008052f587ca4ba90da973c539188deb9551621 100644 --- a/Source/WebCore/loader/CookieJar.h +++ b/Source/WebCore/loader/CookieJar.h -@@ -46,6 +46,7 @@ struct CookieStoreGetOptions; - class NetworkStorageSession; +@@ -48,6 +48,7 @@ class NetworkStorageSession; class StorageSessionProvider; struct SameSiteInfo; + enum class ShouldPartitionCookie : bool; +class ResourceLoader; - class WEBCORE_EXPORT CookieJar : public RefCounted, public CanMakeWeakPtr { + class WEBCORE_EXPORT CookieJar : public RefCountedAndCanMakeWeakPtr { public: -@@ -78,6 +79,9 @@ public: +@@ -80,6 +81,9 @@ public: virtual void clearCache() { } virtual void clearCacheForHost(const String&) { } @@ -5474,10 +5347,10 @@ index 2b0060e70df5765f37426eb32c98540dd3a51356..e4682fb4fad491c906ea4b5b1e98c063 protected: static SameSiteInfo sameSiteInfo(const Document&, IsForDOMCookieAccess = IsForDOMCookieAccess::No); diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp -index 1d674f45b41aa4dbd9c864e7da1af9cef5d6d127..2a004184f256d909ca19de77913162adde5d8486 100644 +index 5aac9a91d7049e7ae7e3f98023db100b53db0e8d..dd4b841a49a8087aa2573ffd725a6351380a3724 100644 --- a/Source/WebCore/loader/DocumentLoader.cpp +++ b/Source/WebCore/loader/DocumentLoader.cpp -@@ -769,8 +769,10 @@ void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const Resourc +@@ -767,8 +767,10 @@ void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const Resourc if (!didReceiveRedirectResponse) return completionHandler(WTFMove(newRequest)); @@ -5488,7 +5361,7 @@ index 1d674f45b41aa4dbd9c864e7da1af9cef5d6d127..2a004184f256d909ca19de77913162ad switch (navigationPolicyDecision) { case NavigationPolicyDecision::IgnoreLoad: case NavigationPolicyDecision::LoadWillContinueInAnotherProcess: -@@ -1538,11 +1540,17 @@ void DocumentLoader::detachFromFrame(LoadWillContinueInAnotherProcess loadWillCo +@@ -1558,11 +1560,17 @@ void DocumentLoader::detachFromFrame(LoadWillContinueInAnotherProcess loadWillCo if (auto navigationID = std::exchange(m_navigationID, { })) m_frame->loader().client().documentLoaderDetached(*navigationID, loadWillContinueInAnotherProcess); @@ -5509,23 +5382,23 @@ index 1d674f45b41aa4dbd9c864e7da1af9cef5d6d127..2a004184f256d909ca19de77913162ad { m_navigationID = navigationID; diff --git a/Source/WebCore/loader/DocumentLoader.h b/Source/WebCore/loader/DocumentLoader.h -index ef3d4036774db95ef807ad01744f1a9ce715fd81..50d78b5c277d034b8455e2df6f3dbf3d8425ea29 100644 +index 710b76ba378d0242be7b9fb469203fcd9ec18252..23ebc0f38d5a5a19b23c748149fbbc8aa36059df 100644 --- a/Source/WebCore/loader/DocumentLoader.h +++ b/Source/WebCore/loader/DocumentLoader.h -@@ -217,6 +217,8 @@ public: +@@ -218,6 +218,8 @@ public: WEBCORE_EXPORT virtual void detachFromFrame(LoadWillContinueInAnotherProcess); + void replacedByFragmentNavigation(LocalFrame&); + WEBCORE_EXPORT FrameLoader* frameLoader() const; - CheckedPtr checkedFrameLoader() const; + RefPtr protectedFrameLoader() const; WEBCORE_EXPORT SubresourceLoader* mainResourceLoader() const; diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp -index 4061749da911827143c27b1db9c685a08c9bde6c..060da14ddac0bcf30f010ed9e65cc652b767a8bd 100644 +index dee3c2e19c47f3451a2a1f52c101064dcd74c8e1..891f10b1871118cadaec7abc0a61016547b93b9f 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp -@@ -1306,6 +1306,7 @@ void FrameLoader::loadInSameDocument(URL url, RefPtr stat +@@ -1322,6 +1322,7 @@ void FrameLoader::loadInSameDocument(URL url, RefPtr stat } m_client->dispatchDidNavigateWithinPage(); @@ -5533,7 +5406,7 @@ index 4061749da911827143c27b1db9c685a08c9bde6c..060da14ddac0bcf30f010ed9e65cc652 document->statePopped(stateObject ? stateObject.releaseNonNull() : SerializedScriptValue::nullValue()); m_client->dispatchDidPopStateWithinPage(); -@@ -1828,6 +1829,7 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t +@@ -1850,6 +1851,7 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t const String& httpMethod = loader->request().httpMethod(); if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker().loadType(), newURL)) { @@ -5541,17 +5414,17 @@ index 4061749da911827143c27b1db9c685a08c9bde6c..060da14ddac0bcf30f010ed9e65cc652 RefPtr oldDocumentLoader = m_documentLoader; NavigationAction action { frame->protectedDocument().releaseNonNull(), loader->request(), InitiatedByMainFrame::Unknown, loader->isRequestFromClientOrUserInput(), policyChecker().loadType(), isFormSubmission }; -@@ -1864,7 +1866,9 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t - } +@@ -1887,7 +1889,9 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t - RELEASE_ASSERT(!isBackForwardLoadType(policyChecker().loadType()) || frame->history().provisionalItem()); + auto policyDecisionMode = loader->triggeringAction().isFromNavigationAPI() ? PolicyDecisionMode::Synchronous : PolicyDecisionMode::Asynchronous; + RELEASE_ASSERT(!isBackForwardLoadType(policyChecker().loadType()) || history().provisionalItem()); + InspectorInstrumentation::willCheckNavigationPolicy(m_frame); policyChecker().checkNavigationPolicy(ResourceRequest(loader->request()), ResourceResponse { } /* redirectResponse */, loader, WTFMove(formState), [this, frame, allowNavigationToInvalidURL, completionHandler = completionHandlerCaller.release()] (const ResourceRequest& request, WeakPtr&& weakFormState, NavigationPolicyDecision navigationPolicyDecision) mutable { + InspectorInstrumentation::didCheckNavigationPolicy(m_frame, navigationPolicyDecision != NavigationPolicyDecision::ContinueLoad); continueLoadAfterNavigationPolicy(request, RefPtr { weakFormState.get() }.get(), navigationPolicyDecision, allowNavigationToInvalidURL); completionHandler(); - }, PolicyDecisionMode::Asynchronous); -@@ -3148,10 +3152,15 @@ String FrameLoader::userAgent(const URL& url) const + }, policyDecisionMode); +@@ -3178,10 +3182,15 @@ String FrameLoader::userAgent(const URL& url) const String FrameLoader::navigatorPlatform() const { @@ -5569,7 +5442,7 @@ index 4061749da911827143c27b1db9c685a08c9bde6c..060da14ddac0bcf30f010ed9e65cc652 } void FrameLoader::dispatchOnloadEvents() -@@ -3615,6 +3624,8 @@ void FrameLoader::receivedMainResourceError(const ResourceError& error, LoadWill +@@ -3655,6 +3664,8 @@ void FrameLoader::receivedMainResourceError(const ResourceError& error, LoadWill checkCompleted(); if (frame->page()) checkLoadComplete(loadWillContinueInAnotherProcess); @@ -5578,7 +5451,7 @@ index 4061749da911827143c27b1db9c685a08c9bde6c..060da14ddac0bcf30f010ed9e65cc652 } void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, const SecurityOrigin* requesterOrigin, bool shouldContinue, NavigationHistoryBehavior historyHandling) -@@ -4499,9 +4510,6 @@ String FrameLoader::referrer() const +@@ -4538,9 +4549,6 @@ String FrameLoader::referrer() const void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() { @@ -5588,7 +5461,7 @@ index 4061749da911827143c27b1db9c685a08c9bde6c..060da14ddac0bcf30f010ed9e65cc652 Vector> worlds; ScriptController::getAllWorlds(worlds); for (auto& world : worlds) -@@ -4511,13 +4519,12 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() +@@ -4550,13 +4558,12 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world) { Ref frame = m_frame.get(); @@ -5621,10 +5494,10 @@ index 91340dc21042f545592b442bc42dbceed06219b2..f3591fe333761b10a25ddaf4a4f8d721 virtual bool shouldPerformSecurityChecks() const { return false; } virtual bool havePerformedSecurityChecks(const ResourceResponse&) const { return false; } diff --git a/Source/WebCore/loader/NavigationScheduler.cpp b/Source/WebCore/loader/NavigationScheduler.cpp -index f8dc5dbb8e4583bc8d595cee184adf58aa765c6c..8c2d54e5d2543b71a733e7356c99e3c1b7642341 100644 +index 9c950ef94e1f1257ade5560b2ac2c8f57d15c352..79d0034559c5ec7e1a9ee26452a87a2e73d52ca4 100644 --- a/Source/WebCore/loader/NavigationScheduler.cpp +++ b/Source/WebCore/loader/NavigationScheduler.cpp -@@ -766,7 +766,7 @@ void NavigationScheduler::startTimer() +@@ -806,7 +806,7 @@ void NavigationScheduler::startTimer() Seconds delay = 1_s * m_redirect->delay(); m_timer.startOneShot(delay); @@ -5633,24 +5506,12 @@ index f8dc5dbb8e4583bc8d595cee184adf58aa765c6c..8c2d54e5d2543b71a733e7356c99e3c1 m_redirect->didStartTimer(frame, m_timer); // m_redirect may be null on return (e.g. the client canceled the load) } -diff --git a/Source/WebCore/loader/PolicyChecker.cpp b/Source/WebCore/loader/PolicyChecker.cpp -index 8f9d997be3da9d2374e1fb50d48c48cdc6542559..4aae7eef8933ddd6a4cae28bc4ef43d3567fda68 100644 ---- a/Source/WebCore/loader/PolicyChecker.cpp -+++ b/Source/WebCore/loader/PolicyChecker.cpp -@@ -46,6 +46,7 @@ - #include "HTMLFrameOwnerElement.h" - #include "HTMLPlugInElement.h" - #include "HitTestResult.h" -+#include "InspectorInstrumentation.h" - #include "LocalDOMWindow.h" - #include "LocalFrame.h" - #include "LocalFrameLoaderClient.h" diff --git a/Source/WebCore/loader/ProgressTracker.cpp b/Source/WebCore/loader/ProgressTracker.cpp -index b74c5258454b0df9f74aa8a5297674b733925685..b6c3999745368c7f7e2e6176bfca6dc09c49f539 100644 +index 171c80cd90bdc8cc16c5e037b25f07faef0dec4e..0869f1be1699dd1548a2e4df6612d7fff42e3093 100644 --- a/Source/WebCore/loader/ProgressTracker.cpp +++ b/Source/WebCore/loader/ProgressTracker.cpp -@@ -161,6 +161,8 @@ void ProgressTracker::progressCompleted(LocalFrame& frame) - if (!m_numProgressTrackedFrames || m_originatingProgressFrame == &frame) +@@ -163,6 +163,8 @@ void ProgressTracker::progressCompleted(LocalFrame& frame) + if (!m_numProgressTrackedFrames || originatingProgressFrame == &frame) finalProgressComplete(); + InspectorInstrumentation::frameStoppedLoading(frame); @@ -5658,20 +5519,20 @@ index b74c5258454b0df9f74aa8a5297674b733925685..b6c3999745368c7f7e2e6176bfca6dc0 m_client->didChangeEstimatedProgress(); } -@@ -187,8 +189,6 @@ void ProgressTracker::finalProgressComplete() - m_client->progressFinished(*frame); - protectedPage()->progressFinished(*frame); - frame->checkedLoader()->loadProgressingStatusChanged(); +@@ -189,8 +191,6 @@ void ProgressTracker::finalProgressComplete() + m_client->progressFinished(*frame); + protectedPage()->progressFinished(*frame); + frame->protectedLoader()->loadProgressingStatusChanged(); - -- InspectorInstrumentation::frameStoppedLoading(*frame); +- InspectorInstrumentation::frameStoppedLoading(*frame); + } } - void ProgressTracker::incrementProgress(ResourceLoaderIdentifier identifier, const ResourceResponse& response) diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp -index 3d811dc807fe10e78221357f76e6851e5788b43e..a1bd9d168a1faa39bc8d122da5e3e8192eb392ce 100644 +index 2b96086b987dca1f53d68599afa751ba84a083f9..2a44a06c6d5a462f76d39c7100ffc495dd874c81 100644 --- a/Source/WebCore/loader/cache/CachedResourceLoader.cpp +++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp -@@ -1136,8 +1136,11 @@ ResourceErrorOr> CachedResourceLoader::requ +@@ -1158,8 +1158,11 @@ ResourceErrorOr> CachedResourceLoader::requ request.updateReferrerPolicy(document() ? document()->referrerPolicy() : ReferrerPolicy::Default); @@ -5685,7 +5546,7 @@ index 3d811dc807fe10e78221357f76e6851e5788b43e..a1bd9d168a1faa39bc8d122da5e3e819 if (RefPtr documentLoader = m_documentLoader.get()) { bool madeHTTPS { request.resourceRequest().wasSchemeOptimisticallyUpgraded() }; -@@ -1754,8 +1757,9 @@ Vector> CachedResourceLoader::allCachedSVGImages() const +@@ -1785,8 +1788,9 @@ Vector> CachedResourceLoader::allCachedSVGImages() const ResourceErrorOr> CachedResourceLoader::preload(CachedResource::Type type, CachedResourceRequest&& request) { @@ -5698,10 +5559,10 @@ index 3d811dc807fe10e78221357f76e6851e5788b43e..a1bd9d168a1faa39bc8d122da5e3e819 ASSERT(m_document); if (request.charset().isEmpty() && m_document && (type == CachedResource::Type::Script || type == CachedResource::Type::CSSStyleSheet)) diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h -index bcc9390a5c7b00e0f3d41baea920453e7b3ac73a..07898280d090a78949876042a64103d4ead18d7f 100644 +index 87eea1d9d7205eff67801b59345a0c3aa097eda1..4d17e0234a86f22abf874c6b08386b5410d2f771 100644 --- a/Source/WebCore/page/ChromeClient.h +++ b/Source/WebCore/page/ChromeClient.h -@@ -341,7 +341,7 @@ public: +@@ -352,7 +352,7 @@ public: #endif #if ENABLE(ORIENTATION_EVENTS) @@ -5711,10 +5572,10 @@ index bcc9390a5c7b00e0f3d41baea920453e7b3ac73a..07898280d090a78949876042a64103d4 #if ENABLE(INPUT_TYPE_COLOR) diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp -index cedf16dffeceb7941de7eca75f6c6800ecacf06f..03296e2cc70e9bd4468ff6161a16378077b0f69c 100644 +index 27a216f1047914aef7ebfe50e2273368da439d49..4de0ff57188dbbfe73da33f49a6c6e5dbb178194 100644 --- a/Source/WebCore/page/EventHandler.cpp +++ b/Source/WebCore/page/EventHandler.cpp -@@ -4372,6 +4372,12 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr +@@ -4454,6 +4454,12 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr if (!document) return false; @@ -5727,7 +5588,15 @@ index cedf16dffeceb7941de7eca75f6c6800ecacf06f..03296e2cc70e9bd4468ff6161a163780 dragState().dataTransfer = DataTransfer::createForDrag(*document); auto hasNonDefaultPasteboardData = HasNonDefaultPasteboardData::No; -@@ -5001,7 +5007,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve +@@ -5040,6 +5046,7 @@ static HitTestResult hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& + return result; + } + ++WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEvent& event) + { + Ref frame = m_frame.get(); +@@ -5114,7 +5121,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap. unsigned touchPointTargetKey = point.id() + 1; @@ -5736,7 +5605,7 @@ index cedf16dffeceb7941de7eca75f6c6800ecacf06f..03296e2cc70e9bd4468ff6161a163780 bool pointerCancelled = false; #endif RefPtr touchTarget; -@@ -5048,7 +5054,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve +@@ -5161,7 +5168,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve // we also remove it from the map. touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey); @@ -5745,7 +5614,7 @@ index cedf16dffeceb7941de7eca75f6c6800ecacf06f..03296e2cc70e9bd4468ff6161a163780 HitTestResult result = hitTestResultAtPoint(pagePoint, hitType | HitTestRequest::Type::AllowChildFrameContent); pointerTarget = result.targetElement(); pointerCancelled = (pointerTarget != touchTarget); -@@ -5071,7 +5077,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve +@@ -5184,7 +5191,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve if (!targetFrame) continue; @@ -5754,11 +5623,19 @@ index cedf16dffeceb7941de7eca75f6c6800ecacf06f..03296e2cc70e9bd4468ff6161a163780 // FIXME: WPE currently does not send touch stationary events, so create a naive TouchReleased PlatformTouchPoint // on release if the hit test result changed since the previous TouchPressed or TouchMoved if (pointState == PlatformTouchPoint::TouchReleased && pointerCancelled) { +@@ -5274,6 +5281,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve + + return swallowedEvent; + } ++WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + #endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) + + #if ENABLE(TOUCH_EVENTS) diff --git a/Source/WebCore/page/FocusController.cpp b/Source/WebCore/page/FocusController.cpp -index c911a4a6ac3f89485cd69917d1f50145b0779b7e..081c8e9a23a5a5d8f4ccd2205016ca0acf2ce64a 100644 +index 1e2dd0f272078b2b4cbc11957f2458088b4c99c4..e736ffb95a51650c8365a55251ca692b152223ca 100644 --- a/Source/WebCore/page/FocusController.cpp +++ b/Source/WebCore/page/FocusController.cpp -@@ -581,13 +581,14 @@ bool FocusController::relinquishFocusToChrome(FocusDirection direction) +@@ -586,13 +586,14 @@ bool FocusController::relinquishFocusToChrome(FocusDirection direction) return false; Ref page = m_page.get(); @@ -5776,19 +5653,19 @@ index c911a4a6ac3f89485cd69917d1f50145b0779b7e..081c8e9a23a5a5d8f4ccd2205016ca0a } diff --git a/Source/WebCore/page/FrameSnapshotting.cpp b/Source/WebCore/page/FrameSnapshotting.cpp -index 084db825e36bd46126fea95fc7183bf2e931be7e..dac3caef67600f8c7c945fd857a91140a23d0303 100644 +index 0c099f95827d6f9fe307704ef9d7754fbb3d24f7..f14fd4dba17985d51d824a9b7c32853a33f4008a 100644 --- a/Source/WebCore/page/FrameSnapshotting.cpp +++ b/Source/WebCore/page/FrameSnapshotting.cpp -@@ -115,7 +115,7 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& +@@ -111,7 +111,7 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& // Other paint behaviors are set by paintContentsForSnapshot. frame.view()->setPaintBehavior(paintBehavior); - float scaleFactor = frame.page()->deviceScaleFactor(); + float scaleFactor = options.flags.contains(SnapshotFlags::OmitDeviceScaleFactor) ? 1 : frame.page()->deviceScaleFactor(); + if (options.flags.contains(SnapshotFlags::PaintWith3xBaseScale)) + scaleFactor = 3; - if (frame.page()->delegatesScaling()) - scaleFactor *= frame.page()->pageScaleFactor(); -@@ -130,7 +130,13 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& +@@ -129,7 +129,13 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& if (!buffer) return nullptr; @@ -5802,7 +5679,7 @@ index 084db825e36bd46126fea95fc7183bf2e931be7e..dac3caef67600f8c7c945fd857a91140 if (!clipRects.isEmpty()) { Path clipPath; -@@ -139,7 +145,10 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& +@@ -138,7 +144,10 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& buffer->context().clipPath(clipPath); } @@ -5815,19 +5692,19 @@ index 084db825e36bd46126fea95fc7183bf2e931be7e..dac3caef67600f8c7c945fd857a91140 } diff --git a/Source/WebCore/page/FrameSnapshotting.h b/Source/WebCore/page/FrameSnapshotting.h -index 5b365008debe6b8d5a95a572a4c2725b0a7a519d..2c6ad49a45a1759f446aced179c0c5a7bfb4b07a 100644 +index 3ab70c27fef52f5d933cd2338a7c2f96e2debc88..39fc13df5ce132f8d028cd5039c607fe8963ddcf 100644 --- a/Source/WebCore/page/FrameSnapshotting.h +++ b/Source/WebCore/page/FrameSnapshotting.h -@@ -55,6 +55,7 @@ enum class SnapshotFlags : uint16_t { - Shareable = 1 << 7, +@@ -56,6 +56,7 @@ enum class SnapshotFlags : uint16_t { Accelerated = 1 << 8, ExcludeReplacedContent = 1 << 9, -+ OmitDeviceScaleFactor = 1 << 10, + PaintWith3xBaseScale = 1 << 10, ++ OmitDeviceScaleFactor = 1 << 11, }; struct SnapshotOptions { diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp -index 709a8aca3d10170ce8394efaeb8eaa0eff9bfacf..40b2ccc937b36b17686cc2231e6f33ebb3e6f712 100644 +index 7cffefe901da03913b16cbe560234ebf97ae7dc6..c6694621e0d39974785fbc5472708551b915f75b 100644 --- a/Source/WebCore/page/History.cpp +++ b/Source/WebCore/page/History.cpp @@ -32,6 +32,7 @@ @@ -5848,7 +5725,7 @@ index 709a8aca3d10170ce8394efaeb8eaa0eff9bfacf..40b2ccc937b36b17686cc2231e6f33eb } diff --git a/Source/WebCore/page/LocalFrame.cpp b/Source/WebCore/page/LocalFrame.cpp -index 53f47ce0a1a4bccf35e183bdb1e7d7ea3208e7ed..9ce65588de61f0c2e8f6a7ee804c93c6a5520d2e 100644 +index 4af71417f15e0d93366168e3c22442a67c3dc77c..c002ef7b769b4b7e1d63d7c5ba42bedaef3f4035 100644 --- a/Source/WebCore/page/LocalFrame.cpp +++ b/Source/WebCore/page/LocalFrame.cpp @@ -41,6 +41,7 @@ @@ -5867,23 +5744,23 @@ index 53f47ce0a1a4bccf35e183bdb1e7d7ea3208e7ed..9ce65588de61f0c2e8f6a7ee804c93c6 #include "HTMLAttachmentElement.h" #include "HTMLFormControlElement.h" #include "HTMLFormElement.h" -@@ -77,6 +79,7 @@ +@@ -79,6 +81,7 @@ #include "Logging.h" #include "Navigator.h" #include "NodeList.h" +#include "NodeRenderStyle.h" #include "NodeTraversal.h" #include "Page.h" - #include "ProcessWarming.h" -@@ -189,6 +192,7 @@ LocalFrame::LocalFrame(Page& page, ClientCreator&& clientCreator, FrameIdentifie + #include "ProcessSyncClient.h" +@@ -200,6 +203,7 @@ LocalFrame::LocalFrame(Page& page, ClientCreator&& clientCreator, FrameIdentifie void LocalFrame::init() { + InspectorInstrumentation::frameAttached(this); - checkedLoader()->init(); + protectedLoader()->init(); } -@@ -405,7 +409,7 @@ void LocalFrame::orientationChanged() +@@ -421,7 +425,7 @@ void LocalFrame::orientationChanged() IntDegrees LocalFrame::orientation() const { if (RefPtr page = this->page()) @@ -5892,9 +5769,9 @@ index 53f47ce0a1a4bccf35e183bdb1e7d7ea3208e7ed..9ce65588de61f0c2e8f6a7ee804c93c6 return 0; } #endif // ENABLE(ORIENTATION_EVENTS) -@@ -1370,6 +1374,362 @@ void LocalFrame::updateSandboxFlags(SandboxFlags flags, NotifyUIProcess notifyUI - m_sandboxFlags = flags; - } +@@ -1428,6 +1432,364 @@ void LocalFrame::showResourceMonitoringError() + + #endif +#if !PLATFORM(IOS_FAMILY) + @@ -5942,6 +5819,7 @@ index 53f47ce0a1a4bccf35e183bdb1e7d7ea3208e7ed..9ce65588de61f0c2e8f6a7ee804c93c6 + return true; +} + ++WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN +Node* LocalFrame::qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier& nodeQualifierFunction, ShouldApproximate shouldApproximate, ShouldFindRootEditableElement shouldFindRootEditableElement) +{ + adjustedViewportLocation = viewportLocation; @@ -6053,6 +5931,7 @@ index 53f47ce0a1a4bccf35e183bdb1e7d7ea3208e7ed..9ce65588de61f0c2e8f6a7ee804c93c6 + + return approximateNode; +} ++WTF_ALLOW_UNSAFE_BUFFER_USAGE_END + +Node* LocalFrame::deepestNodeAtLocation(const FloatPoint& viewportLocation) +{ @@ -6256,7 +6135,7 @@ index 53f47ce0a1a4bccf35e183bdb1e7d7ea3208e7ed..9ce65588de61f0c2e8f6a7ee804c93c6 #undef FRAME_RELEASE_LOG_ERROR diff --git a/Source/WebCore/page/LocalFrame.h b/Source/WebCore/page/LocalFrame.h -index 38fe2680b461f6a319f6b976412fff6a5af9950f..ca63f835abf84b00fb7e57361b1969400ceb8f4a 100644 +index 3611617df72251227ebd6a2f8c32bc9ab3da48aa..9b59492c8846cd8e91e58602010eb39b103747b7 100644 --- a/Source/WebCore/page/LocalFrame.h +++ b/Source/WebCore/page/LocalFrame.h @@ -28,8 +28,10 @@ @@ -6270,15 +6149,7 @@ index 38fe2680b461f6a319f6b976412fff6a5af9950f..ca63f835abf84b00fb7e57361b196940 #include "ScrollTypes.h" #include "UserScriptTypes.h" #include -@@ -71,7 +73,6 @@ namespace WebCore { - class Color; - class LocalDOMWindow; - class DataDetectionResultsStorage; --class Document; - class Editor; - class Element; - class EventHandler; -@@ -115,8 +116,8 @@ enum { +@@ -116,8 +118,8 @@ enum { }; enum OverflowScrollAction { DoNotPerformOverflowScroll, PerformOverflowScroll }; @@ -6288,7 +6159,7 @@ index 38fe2680b461f6a319f6b976412fff6a5af9950f..ca63f835abf84b00fb7e57361b196940 class LocalFrame final : public Frame { public: -@@ -226,10 +227,6 @@ public: +@@ -226,10 +228,6 @@ public: WEBCORE_EXPORT DataDetectionResultsStorage& dataDetectionResults(); #endif @@ -6299,7 +6170,7 @@ index 38fe2680b461f6a319f6b976412fff6a5af9950f..ca63f835abf84b00fb7e57361b196940 WEBCORE_EXPORT Node* deepestNodeAtLocation(const FloatPoint& viewportLocation); WEBCORE_EXPORT Node* nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* = nullptr); WEBCORE_EXPORT Node* nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); -@@ -237,6 +234,10 @@ public: +@@ -237,6 +235,10 @@ public: WEBCORE_EXPORT Node* nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation); WEBCORE_EXPORT Node* approximateNodeAtViewportLocationLegacy(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); @@ -6310,7 +6181,7 @@ index 38fe2680b461f6a319f6b976412fff6a5af9950f..ca63f835abf84b00fb7e57361b196940 WEBCORE_EXPORT NSArray *wordsInCurrentParagraph() const; WEBCORE_EXPORT CGRect renderRectForPoint(CGPoint, bool* isReplaced, float* fontSize) const; -@@ -304,6 +305,7 @@ public: +@@ -304,6 +306,7 @@ public: WEBCORE_EXPORT FloatSize screenSize() const; void setOverrideScreenSize(FloatSize&&); @@ -6318,7 +6189,7 @@ index 38fe2680b461f6a319f6b976412fff6a5af9950f..ca63f835abf84b00fb7e57361b196940 void selfOnlyRef(); void selfOnlyDeref(); -@@ -363,7 +365,6 @@ private: +@@ -371,7 +374,6 @@ private: #if ENABLE(DATA_DETECTION) std::unique_ptr m_dataDetectionResults; #endif @@ -6326,7 +6197,7 @@ index 38fe2680b461f6a319f6b976412fff6a5af9950f..ca63f835abf84b00fb7e57361b196940 void betterApproximateNode(const IntPoint& testPoint, const NodeQualifier&, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect); bool hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult&, IntPoint& center); -@@ -371,6 +372,7 @@ private: +@@ -379,6 +381,7 @@ private: enum class ShouldFindRootEditableElement : bool { No, Yes }; Node* qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier&, ShouldApproximate, ShouldFindRootEditableElement = ShouldFindRootEditableElement::Yes); @@ -6335,11 +6206,11 @@ index 38fe2680b461f6a319f6b976412fff6a5af9950f..ca63f835abf84b00fb7e57361b196940 ViewportArguments m_viewportArguments; diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp -index 93122d37376bc11488f27dea245534d7657e281d..1cccbbb3379a468bca19903ab1eb34cdd285a93c 100644 +index 7cd56bf4f7fd05b85e61c26dbf1403e17c041867..0152d48d65ed21173df99ebec3e5abe29f7e6b2e 100644 --- a/Source/WebCore/page/Page.cpp +++ b/Source/WebCore/page/Page.cpp -@@ -609,6 +609,45 @@ void Page::setOverrideViewportArguments(const std::optional& - document->updateViewportArguments(); +@@ -637,6 +637,45 @@ void Page::setOverrideViewportArguments(const std::optional& + localTopDocument->updateViewportArguments(); } +FloatSize Page::screenSize() @@ -6384,8 +6255,8 @@ index 93122d37376bc11488f27dea245534d7657e281d..1cccbbb3379a468bca19903ab1eb34cd ScrollingCoordinator* Page::scrollingCoordinator() { if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) { -@@ -3974,6 +4013,26 @@ void Page::setUseDarkAppearanceOverride(std::optional valueOverride) - #endif +@@ -4126,6 +4165,26 @@ void Page::setUseDarkAppearanceOverride(std::optional valueOverride) + appearanceDidChange(); } +void Page::setUseReducedMotionOverride(std::optional valueOverride) @@ -6412,10 +6283,10 @@ index 93122d37376bc11488f27dea245534d7657e281d..1cccbbb3379a468bca19903ab1eb34cd { if (insets == m_fullscreenInsets) diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h -index 55887f532ee42163e7ea0c34a31f1c8bdc0d808f..cc0d6b05a2132c96e45e956cbccabe61df434953 100644 +index 7a117d8981605065213f521200776f8373439400..694fffe20f596f8e9c655181ed2b5917949859d7 100644 --- a/Source/WebCore/page/Page.h +++ b/Source/WebCore/page/Page.h -@@ -354,6 +354,9 @@ public: +@@ -364,6 +364,9 @@ public: const std::optional& overrideViewportArguments() const { return m_overrideViewportArguments; } WEBCORE_EXPORT void setOverrideViewportArguments(const std::optional&); @@ -6425,7 +6296,7 @@ index 55887f532ee42163e7ea0c34a31f1c8bdc0d808f..cc0d6b05a2132c96e45e956cbccabe61 static void refreshPlugins(bool reload); WEBCORE_EXPORT PluginData& pluginData(); void clearPluginData(); -@@ -422,6 +425,10 @@ public: +@@ -454,6 +457,10 @@ public: #if ENABLE(DRAG_SUPPORT) DragController& dragController() { return m_dragController.get(); } const DragController& dragController() const { return m_dragController.get(); } @@ -6436,8 +6307,8 @@ index 55887f532ee42163e7ea0c34a31f1c8bdc0d808f..cc0d6b05a2132c96e45e956cbccabe61 #endif FocusController& focusController() const { return *m_focusController; } WEBCORE_EXPORT CheckedRef checkedFocusController() const; -@@ -605,6 +612,10 @@ public: - WEBCORE_EXPORT void effectiveAppearanceDidChange(bool useDarkAppearance, bool useElevatedUserInterfaceLevel); +@@ -639,6 +646,10 @@ public: + WEBCORE_EXPORT void setUseColorAppearance(bool useDarkAppearance, bool useElevatedUserInterfaceLevel); bool defaultUseDarkAppearance() const { return m_useDarkAppearance; } void setUseDarkAppearanceOverride(std::optional); + std::optional useReducedMotionOverride() const { return m_useReducedMotionOverride; } @@ -6447,7 +6318,7 @@ index 55887f532ee42163e7ea0c34a31f1c8bdc0d808f..cc0d6b05a2132c96e45e956cbccabe61 #if ENABLE(TEXT_AUTOSIZING) float textAutosizingWidth() const { return m_textAutosizingWidth; } -@@ -1057,6 +1068,11 @@ public: +@@ -1094,6 +1105,11 @@ public: WEBCORE_EXPORT void setInteractionRegionsEnabled(bool); #endif @@ -6459,7 +6330,7 @@ index 55887f532ee42163e7ea0c34a31f1c8bdc0d808f..cc0d6b05a2132c96e45e956cbccabe61 #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY) DeviceOrientationUpdateProvider* deviceOrientationUpdateProvider() const { return m_deviceOrientationUpdateProvider.get(); } #endif -@@ -1289,6 +1305,9 @@ private: +@@ -1358,6 +1374,9 @@ private: #if ENABLE(DRAG_SUPPORT) UniqueRef m_dragController; @@ -6469,7 +6340,7 @@ index 55887f532ee42163e7ea0c34a31f1c8bdc0d808f..cc0d6b05a2132c96e45e956cbccabe61 #endif std::unique_ptr m_focusController; #if ENABLE(CONTEXT_MENUS) -@@ -1369,6 +1388,8 @@ private: +@@ -1435,6 +1454,8 @@ private: bool m_useElevatedUserInterfaceLevel { false }; bool m_useDarkAppearance { false }; std::optional m_useDarkAppearanceOverride; @@ -6478,7 +6349,7 @@ index 55887f532ee42163e7ea0c34a31f1c8bdc0d808f..cc0d6b05a2132c96e45e956cbccabe61 #if ENABLE(TEXT_AUTOSIZING) float m_textAutosizingWidth { 0 }; -@@ -1549,6 +1570,11 @@ private: +@@ -1615,6 +1636,11 @@ private: #endif std::optional m_overrideViewportArguments; @@ -6491,10 +6362,10 @@ index 55887f532ee42163e7ea0c34a31f1c8bdc0d808f..cc0d6b05a2132c96e45e956cbccabe61 #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY) RefPtr m_deviceOrientationUpdateProvider; diff --git a/Source/WebCore/page/PageConsoleClient.cpp b/Source/WebCore/page/PageConsoleClient.cpp -index 52ceeb42346f843bec6734584e7d36beb7845abd..5bf7ff1870fdd011ea16419ab517bfa6ff51d874 100644 +index 585c224c08f5a8f8d8e660fa627c264f3386d1ef..26a58fb2fa2a15468a70912f879fe01f4915d0ca 100644 --- a/Source/WebCore/page/PageConsoleClient.cpp +++ b/Source/WebCore/page/PageConsoleClient.cpp -@@ -437,4 +437,9 @@ Ref PageConsoleClient::protectedPage() const +@@ -456,4 +456,9 @@ Ref PageConsoleClient::protectedPage() const return m_page.get(); } @@ -6517,10 +6388,10 @@ index 153fc36199f26adbfb61cbef6744ffe31a68b951..cc667e06700013fd5e994467e19536d2 Ref protectedPage() const; diff --git a/Source/WebCore/page/PointerCaptureController.cpp b/Source/WebCore/page/PointerCaptureController.cpp -index f1040d32a97110c5b8d802450f36794f1d0f34fd..469c6cc7674578e5f2623a23c3f151bc65d278c1 100644 +index 671c31a3af5253634ffd9a55b99aa9462f4e5f9a..faea774b6987408fac036fd19c8f1cefffa917b1 100644 --- a/Source/WebCore/page/PointerCaptureController.cpp +++ b/Source/WebCore/page/PointerCaptureController.cpp -@@ -198,7 +198,7 @@ bool PointerCaptureController::preventsCompatibilityMouseEventsForIdentifier(Poi +@@ -204,7 +204,7 @@ bool PointerCaptureController::preventsCompatibilityMouseEventsForIdentifier(Poi return capturingData && capturingData->preventsCompatibilityMouseEvents; } @@ -6529,7 +6400,7 @@ index f1040d32a97110c5b8d802450f36794f1d0f34fd..469c6cc7674578e5f2623a23c3f151bc static bool hierarchyHasCapturingEventListeners(Element* target, const AtomString& eventName) { for (RefPtr currentNode = target; currentNode; currentNode = currentNode->parentInComposedTree()) { -@@ -503,7 +503,7 @@ void PointerCaptureController::cancelPointer(PointerID pointerId, const IntPoint +@@ -554,7 +554,7 @@ void PointerCaptureController::cancelPointer(PointerID pointerId, const IntPoint capturingData->pendingTargetOverride = nullptr; capturingData->state = CapturingData::State::Cancelled; @@ -6539,10 +6410,10 @@ index f1040d32a97110c5b8d802450f36794f1d0f34fd..469c6cc7674578e5f2623a23c3f151bc #endif diff --git a/Source/WebCore/page/PointerCaptureController.h b/Source/WebCore/page/PointerCaptureController.h -index 99676da258803e8348ae1fee23e7e3883fb0b888..0477e6dff22db0e7f2d78cb8ecb863ec5fea136f 100644 +index 9245baa0c317bb3dfa8a2a1666953d320cb85ee1..55445eb29e095ef4b6d6918728885a267a3b8183 100644 --- a/Source/WebCore/page/PointerCaptureController.h +++ b/Source/WebCore/page/PointerCaptureController.h -@@ -59,7 +59,7 @@ public: +@@ -60,7 +60,7 @@ public: RefPtr pointerEventForMouseEvent(const MouseEvent&, PointerID, const String& pointerType); @@ -6551,8 +6422,8 @@ index 99676da258803e8348ae1fee23e7e3883fb0b888..0477e6dff22db0e7f2d78cb8ecb863ec void dispatchEventForTouchAtIndex(EventTarget&, const PlatformTouchEvent&, unsigned, bool isPrimary, WindowProxy&, const IntPoint&); #endif -@@ -79,12 +79,12 @@ private: - +@@ -81,12 +81,12 @@ private: + WeakPtr activeDocument; RefPtr pendingTargetOverride; RefPtr targetOverride; -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) @@ -6611,7 +6482,7 @@ index 24ed7c019bea4df52f2883db0e40bdbc2dc74ebd..a788f534d9e0e8124153c7f380b4fdb2 } diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp -index 74e4e43482f969cf90c47d897f8226672d748cff..d2b491a7346677253891f4057b2cdb1d679fe08b 100644 +index a67def78b37298d5efa0b14f337f58471c895169..ddfc9ae5b8391df70b3c6a4be2bcae6ae32b2b7c 100644 --- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp +++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp @@ -347,6 +347,8 @@ bool ContentSecurityPolicy::allowContentSecurityPolicySourceStarToMatchAnyProtoc @@ -6740,7 +6611,7 @@ index 29492dd39b08db28aad2bf2439eb3e2bbcf25ad7..2b603cb8440b1b5057c87fcbd6909c61 ) diff --git a/Source/WebCore/platform/DragData.h b/Source/WebCore/platform/DragData.h -index 34f49853b1d5ac8d8409bbd36d203bf7dfbb08e8..6d2808d510413e89ae9851733437d15b7660cd4a 100644 +index 2ebb3221cb3818f20abc7b7c3307ea7644f49d49..e0bffb6f5adee0b0a202340f633c2def1955b384 100644 --- a/Source/WebCore/platform/DragData.h +++ b/Source/WebCore/platform/DragData.h @@ -47,7 +47,7 @@ typedef void* DragDataRef; @@ -6786,7 +6657,7 @@ index c359242a7967dab94b8dc3c276a6df5473527145..64b0c6a0bfdf27a0305c25e8b8e0cda6 IntSize dragImageSize(DragImageRef) { diff --git a/Source/WebCore/platform/Pasteboard.h b/Source/WebCore/platform/Pasteboard.h -index 33841aa5cc1fc15557514d60096d8274234447c3..2c91d472a24c591215d6f2861aca6f86a00d086a 100644 +index 1b1a1147d4948e9281a114281e95d57d3b0ccf27..e21ccb98542cc582ad2489d301cb29c2b0c03f4b 100644 --- a/Source/WebCore/platform/Pasteboard.h +++ b/Source/WebCore/platform/Pasteboard.h @@ -46,7 +46,7 @@ OBJC_CLASS NSString; @@ -6880,18 +6751,10 @@ index 63ffd6ca32c3baee03db2a9419c4f7e9de45388a..c60c7a8d1f110472117c8c4e969fd05f #endif diff --git a/Source/WebCore/platform/PlatformScreen.cpp b/Source/WebCore/platform/PlatformScreen.cpp -index ae46341ba71c7f6df7c607bd852338cdb7f83fe1..b318c0771192344a6891c1f097cb0b93dabe8237 100644 +index ae46341ba71c7f6df7c607bd852338cdb7f83fe1..a11db190d86f5e3ec4c7cee6c5b3ea93f2380646 100644 --- a/Source/WebCore/platform/PlatformScreen.cpp +++ b/Source/WebCore/platform/PlatformScreen.cpp -@@ -25,6 +25,7 @@ - - #include "config.h" - #include "PlatformScreen.h" -+#include "DeprecatedGlobalSettings.h" - - #if PLATFORM(COCOA) || PLATFORM(GTK) || (PLATFORM(WPE) && ENABLE(WPE_PLATFORM)) - -@@ -73,3 +74,25 @@ const ScreenData* screenData(PlatformDisplayID screenDisplayID) +@@ -73,3 +73,25 @@ const ScreenData* screenData(PlatformDisplayID screenDisplayID) } // namespace WebCore #endif // PLATFORM(COCOA) || PLATFORM(GTK) || (PLATFORM(WPE) && ENABLE(WPE_PLATFORM)) @@ -6918,10 +6781,10 @@ index ae46341ba71c7f6df7c607bd852338cdb7f83fe1..b318c0771192344a6891c1f097cb0b93 +} // namespace WebCore +#endif diff --git a/Source/WebCore/platform/PlatformScreen.h b/Source/WebCore/platform/PlatformScreen.h -index f10a43820dca4bdeafe67b330243a698f3334f5a..a8e3a9b96cd8b3b36174da42abc0ccac6cb5b17c 100644 +index 6ffb85dbfcc01be76ef498f4f7478747912ca7d7..a6e0a3347e36a01b9aeca524747d14ff63f4c529 100644 --- a/Source/WebCore/platform/PlatformScreen.h +++ b/Source/WebCore/platform/PlatformScreen.h -@@ -151,13 +151,18 @@ WEBCORE_EXPORT float screenScaleFactor(UIScreen * = nullptr); +@@ -154,12 +154,16 @@ WEBCORE_EXPORT float screenScaleFactor(UIScreen * = nullptr); #endif #if ENABLE(TOUCH_EVENTS) @@ -6941,8 +6804,6 @@ index f10a43820dca4bdeafe67b330243a698f3334f5a..a8e3a9b96cd8b3b36174da42abc0ccac #endif #endif -+ - } // namespace WebCore diff --git a/Source/WebCore/platform/PlatformTouchEvent.h b/Source/WebCore/platform/PlatformTouchEvent.h index 23f011953c66f401553bedfaef3485af215ae083..a73da2ebe47f0d8dc57f3d0159e8f299abb61c96 100644 --- a/Source/WebCore/platform/PlatformTouchEvent.h @@ -6970,7 +6831,7 @@ index 34715d27b529750fc866db87cd330b5184286771..3eefa218af075f76d98012cdeae7e4b3 // create a PlatformTouchPoint of type TouchCancelled artificially PlatformTouchPoint(unsigned id, State state, IntPoint screenPos, IntPoint pos) diff --git a/Source/WebCore/platform/Skia.cmake b/Source/WebCore/platform/Skia.cmake -index 616a44dba554ac1429c074f1fe9509a3f544ef1e..73c9b605221dbd036713afa9d1935902444833b3 100644 +index 31460a79014b0a8b21fdfe71759af14ff2da46d7..f2594d701502102fed89d711694b64e05a863aaa 100644 --- a/Source/WebCore/platform/Skia.cmake +++ b/Source/WebCore/platform/Skia.cmake @@ -13,6 +13,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS @@ -6980,9 +6841,9 @@ index 616a44dba554ac1429c074f1fe9509a3f544ef1e..73c9b605221dbd036713afa9d1935902 + platform/graphics/skia/ImageBufferUtilitiesSkia.h platform/graphics/skia/SkiaHarfBuzzFont.h platform/graphics/skia/SkiaHarfBuzzFontCache.h - ) + platform/graphics/skia/SkiaPaintingEngine.h diff --git a/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp b/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp -index 8f36dda49adafd4a542e24e3c4dd33d42be00d27..953b6f88f8deb597d2179a8cec7b717b7cf6dc5a 100644 +index 492c5e76290c2379cda40b9663f5f67ff8f66360..096752985edf39960eb4be6eb733ebe3713313cb 100644 --- a/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp +++ b/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp @@ -46,7 +46,7 @@ @@ -7115,7 +6976,7 @@ index 3d0ab7eceaf2a6321685bc362eb9b25600fd98fd..2d7e9a399bf2e9dc3f373d5fa3db99fa namespace WebCore { diff --git a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp -index eb9710f7d61121f2414c8aa6734dc27653e292bb..9c0c7b350a6140681242ce36a180d6866e3e0fc2 100644 +index 3f0b75a0702db1ed10334c80e4813094571f588c..ea5ff6b7e7bd4c3b8babebc294d7d7c94fc6afb6 100644 --- a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp +++ b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp @@ -169,6 +169,33 @@ static Vector stringIndicesFromClusters(const Vector& clusters, @@ -7162,7 +7023,7 @@ index eb9710f7d61121f2414c8aa6734dc27653e292bb..9c0c7b350a6140681242ce36a180d686 // Determine the string for this item. const UChar* str = cp.data() + items[i].iCharPos; diff --git a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp -index 979ec06ecd698b60066dc6775bf1b647624baa56..14d06fdd5b7b7df2a1942ed975cebf117beb4d1f 100644 +index 2b7d3dc70fdfec767d8caa13966c4051ee73aead..7fa8e155bef817c837042c8d6c4dcb84864232bc 100644 --- a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp @@ -37,8 +37,10 @@ @@ -7180,9 +7041,9 @@ index 979ec06ecd698b60066dc6775bf1b647624baa56..14d06fdd5b7b7df2a1942ed975cebf11 } -+static const HashMap& gdkToWindowsKeyCodeMap() ++static const UncheckedKeyHashMap& gdkToWindowsKeyCodeMap() +{ -+ static HashMap* result; ++ static UncheckedKeyHashMap* result; + static std::once_flag once; + std::call_once( + once, @@ -7405,7 +7266,7 @@ index 979ec06ecd698b60066dc6775bf1b647624baa56..14d06fdd5b7b7df2a1942ed975cebf11 + GDK_KEY_Subtitle, + GDK_KEY_Video + }; -+ result = new HashMap(); ++ result = new UncheckedKeyHashMap(); + for (unsigned gdkKeyCode : gdkKeyCodes) { + int winKeyCode = PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(gdkKeyCode); + // If several gdk key codes map to the same win key code first one is used. @@ -7445,19 +7306,6 @@ index 9ea18000578dd47295b2ce4da7fa00b39b5cac81..41bdd2d741b469acb134220df7e0c102 { auto* display = gdk_display_get_default(); if (!display) -diff --git a/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp b/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp -index c65514727c0e915e06c460cba7530f9ae2d8e0e6..7836b21f81e77b869099f78ad6bdd0788df7eb70 100644 ---- a/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp -+++ b/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp -@@ -39,6 +39,8 @@ - - namespace WebCore { - -+ScrollbarThemeGtk::~ScrollbarThemeGtk() = default; -+ - ScrollbarTheme& ScrollbarTheme::nativeTheme() - { - static ScrollbarThemeGtk theme; diff --git a/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp b/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp index ae439e30f1fb239d18e1164e8896dfb272c75673..4cf29eda13d1f2dc2f03750c0ef8985b17de7f50 100644 --- a/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp @@ -7666,7 +7514,7 @@ index ae439e30f1fb239d18e1164e8896dfb272c75673..4cf29eda13d1f2dc2f03750c0ef8985b #endif // USE(LIBWPE) diff --git a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp -index a8674916429908cabb86bd95dc5b3da217e1556b..75cbb518708ebd459b1ed8e3206cdb02e502067d 100644 +index a8674916429908cabb86bd95dc5b3da217e1556b..6a464e2b0c1c45cd4e8effba678b8dde9dd870da 100644 --- a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp +++ b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp @@ -30,9 +30,11 @@ @@ -7685,9 +7533,9 @@ index a8674916429908cabb86bd95dc5b3da217e1556b..75cbb518708ebd459b1ed8e3206cdb02 return 0; } -+static const HashMap& WPEToWindowsKeyCodeMap() ++static const UncheckedKeyHashMap& WPEToWindowsKeyCodeMap() +{ -+ static HashMap* result; ++ static UncheckedKeyHashMap* result; + static std::once_flag once; + std::call_once( + once, @@ -7910,7 +7758,7 @@ index a8674916429908cabb86bd95dc5b3da217e1556b..75cbb518708ebd459b1ed8e3206cdb02 + WPE_KEY_Subtitle, + WPE_KEY_Video + }; -+ result = new HashMap(); ++ result = new UncheckedKeyHashMap(); + for (unsigned WPEKeyCode : WPEKeyCodes) { + int winKeyCode = PlatformKeyboardEvent::windowsKeyCodeForWPEKeyCode(WPEKeyCode); + // If several gdk key codes map to the same win key code first one is used. @@ -7929,7 +7777,7 @@ index a8674916429908cabb86bd95dc5b3da217e1556b..75cbb518708ebd459b1ed8e3206cdb02 { switch (val) { diff --git a/Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp b/Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp -index c62e88f8c3aa40f01618cdaf0c0e22a2404b17ad..02411ac6bb361c2677c269945f665e0a92ccb902 100644 +index 64afe805b4418d9e57cc7a2704498a97162b93ab..86c385359352853d2884226f478168f890b0c8f0 100644 --- a/Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp +++ b/Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp @@ -31,10 +31,18 @@ @@ -7942,9 +7790,9 @@ index c62e88f8c3aa40f01618cdaf0c0e22a2404b17ad..02411ac6bb361c2677c269945f665e0a namespace WebCore { -+static HashMap& sharedPasteboard() ++static UncheckedKeyHashMap& sharedPasteboard() +{ -+ static NeverDestroyed> pasteboard; ++ static NeverDestroyed> pasteboard; + return pasteboard.get(); +} + @@ -7957,10 +7805,9 @@ index c62e88f8c3aa40f01618cdaf0c0e22a2404b17ad..02411ac6bb361c2677c269945f665e0a { - struct wpe_pasteboard_string_vector pasteboardTypes = { nullptr, 0 }; - wpe_pasteboard_get_types(m_pasteboard, &pasteboardTypes); -- -- for (unsigned i = 0; i < pasteboardTypes.length; ++i) { -- auto& typeString = pasteboardTypes.strings[i]; -- types.append(String({ typeString.data, typeString.length })); +- for (auto& typeString : unsafeMakeSpan(pasteboardTypes.strings, pasteboardTypes.length)) { +- const auto length = std::min(static_cast(typeString.length), std::numeric_limits::max()); +- types.append(String({ typeString.data, length })); - } - - wpe_pasteboard_string_vector_free(&pasteboardTypes); @@ -7975,7 +7822,8 @@ index c62e88f8c3aa40f01618cdaf0c0e22a2404b17ad..02411ac6bb361c2677c269945f665e0a - if (!string.length) - return String(); - -- String returnValue({ string.data, string.length }); +- const auto length = std::min(static_cast(string.length), std::numeric_limits::max()); +- String returnValue({ string.data, length }); - - wpe_pasteboard_string_free(&string); - return returnValue; @@ -7984,21 +7832,21 @@ index c62e88f8c3aa40f01618cdaf0c0e22a2404b17ad..02411ac6bb361c2677c269945f665e0a void PlatformPasteboard::write(const PasteboardWebContent& content) { -- static const char plainText[] = "text/plain;charset=utf-8"; -- static const char htmlText[] = "text/html;charset=utf-8"; +- static constexpr auto plainText = "text/plain;charset=utf-8"_s; +- static constexpr auto htmlText = "text/html;charset=utf-8"_s; - - CString textString = content.text.utf8(); - CString markupString = content.markup.utf8(); - -- struct wpe_pasteboard_string_pair pairs[] = { +- std::array pairs = { { - { { nullptr, 0 }, { nullptr, 0 } }, - { { nullptr, 0 }, { nullptr, 0 } }, -- }; +- } }; - wpe_pasteboard_string_initialize(&pairs[0].type, plainText, strlen(plainText)); - wpe_pasteboard_string_initialize(&pairs[0].string, textString.data(), textString.length()); - wpe_pasteboard_string_initialize(&pairs[1].type, htmlText, strlen(htmlText)); - wpe_pasteboard_string_initialize(&pairs[1].string, markupString.data(), markupString.length()); -- struct wpe_pasteboard_string_map map = { pairs, 2 }; +- struct wpe_pasteboard_string_map map = { pairs.data(), pairs.size() }; - - wpe_pasteboard_write(m_pasteboard, &map); - @@ -8032,24 +7880,11 @@ index c62e88f8c3aa40f01618cdaf0c0e22a2404b17ad..02411ac6bb361c2677c269945f665e0a } Vector PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String&) const -diff --git a/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/LibWebRTCProviderGStreamer.h b/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/LibWebRTCProviderGStreamer.h -index 0552842dbe3f3a2c12a504178f5a8ca977e1c4db..2ef3b1b459d8a9b4e86b4556feeb4f0737f05c54 100644 ---- a/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/LibWebRTCProviderGStreamer.h -+++ b/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/LibWebRTCProviderGStreamer.h -@@ -31,6 +31,8 @@ - #include "GStreamerVideoEncoderFactory.h" - #include "LibWebRTCProvider.h" - -+#include "LibWebRTCProvider.h" -+ - namespace WebCore { - - class WEBCORE_EXPORT LibWebRTCProviderGStreamer : public LibWebRTCProvider { diff --git a/Source/WebCore/platform/network/HTTPHeaderMap.cpp b/Source/WebCore/platform/network/HTTPHeaderMap.cpp -index 65679251a5c66afcf60ed4d4267169eefed745f5..2cb9dc1f0e777fd172e52f5a6c8f4d6910c08c47 100644 +index 1178c8fb001994bc9e6166376a367d9bc148913c..fcc6534568cad6b42a819a435f84ba2b9baae6f8 100644 --- a/Source/WebCore/platform/network/HTTPHeaderMap.cpp +++ b/Source/WebCore/platform/network/HTTPHeaderMap.cpp -@@ -236,8 +236,11 @@ void HTTPHeaderMap::add(HTTPHeaderName name, const String& value) +@@ -237,8 +237,11 @@ void HTTPHeaderMap::add(HTTPHeaderName name, const String& value) auto index = m_commonHeaders.findIf([&](auto& header) { return header.key == name; }); @@ -8063,20 +7898,19 @@ index 65679251a5c66afcf60ed4d4267169eefed745f5..2cb9dc1f0e777fd172e52f5a6c8f4d69 m_commonHeaders.append(CommonHeader { name, value }); } diff --git a/Source/WebCore/platform/network/NetworkStorageSession.h b/Source/WebCore/platform/network/NetworkStorageSession.h -index bf887012d2f391eb6169a9e53b40cb3c682e6d70..4954dfb7ed9ee711b126552dc9130f265059d270 100644 +index f14a54120d571c14bb7a721a377a57131760cfca..832b6710f726d4d8a8ccaa35b2f634a7d5604ccb 100644 --- a/Source/WebCore/platform/network/NetworkStorageSession.h +++ b/Source/WebCore/platform/network/NetworkStorageSession.h -@@ -185,6 +185,8 @@ public: +@@ -195,6 +195,7 @@ public: + NetworkingContext* context() const; #endif - + WEBCORE_EXPORT void setCookiesFromResponse(const URL& firstParty, const SameSiteInfo&, const URL&, const String& setCookieValue); -+ + WEBCORE_EXPORT HTTPCookieAcceptPolicy cookieAcceptPolicy() const; WEBCORE_EXPORT void setCookie(const Cookie&); - WEBCORE_EXPORT void setCookies(const Vector&, const URL&, const URL& mainDocumentURL); diff --git a/Source/WebCore/platform/network/ResourceResponseBase.cpp b/Source/WebCore/platform/network/ResourceResponseBase.cpp -index 91cba6cadafd7c3739c2293b6146321b5ba0ea28..a1a52db245a2b480614901b650524872596a6c47 100644 +index 774748f1bb47fdefa53b820db5fc891077125de7..4f9220dace7d300d2326692383944f3a560d8cb8 100644 --- a/Source/WebCore/platform/network/ResourceResponseBase.cpp +++ b/Source/WebCore/platform/network/ResourceResponseBase.cpp @@ -78,6 +78,7 @@ ResourceResponseBase::ResourceResponseBase(std::optional d @@ -8087,7 +7921,7 @@ index 91cba6cadafd7c3739c2293b6146321b5ba0ea28..a1a52db245a2b480614901b650524872 , m_networkLoadMetrics(data && data->networkLoadMetrics ? Box::create(*data->networkLoadMetrics) : Box { }) , m_certificateInfo(data ? data->certificateInfo : std::nullopt) , m_httpStatusCode(data ? data->httpStatusCode : 0) -@@ -896,6 +897,7 @@ std::optional ResourceResponseBase::getResponseData() cons +@@ -901,6 +902,7 @@ std::optional ResourceResponseBase::getResponseData() cons String { m_httpStatusText }, String { m_httpVersion }, HTTPHeaderMap { m_httpHeaderFields }, @@ -8095,7 +7929,7 @@ index 91cba6cadafd7c3739c2293b6146321b5ba0ea28..a1a52db245a2b480614901b650524872 m_networkLoadMetrics ? std::optional(*m_networkLoadMetrics) : std::nullopt, m_source, m_type, -@@ -969,6 +971,11 @@ std::optional Coder Coder httpStatusCode; decoder >> httpStatusCode; if (!httpStatusCode) -@@ -1023,6 +1030,7 @@ std::optional Coder Coder m_networkLoadMetrics; mutable std::optional m_certificateInfo; -@@ -292,7 +297,7 @@ struct ResourceResponseData { +@@ -294,7 +299,7 @@ struct ResourceResponseData { ResourceResponseData() = default; ResourceResponseData(ResourceResponseData&&) = default; ResourceResponseData& operator=(ResourceResponseData&&) = default; @@ -8140,7 +7974,7 @@ index 95c24f85913c09bdf2e7b9e6c4e308d9528b06af..d6da8d829b0f40a9f234429aa97c5bd0 : url(WTFMove(url)) , mimeType(WTFMove(mimeType)) , expectedContentLength(expectedContentLength) -@@ -301,6 +306,7 @@ struct ResourceResponseData { +@@ -303,6 +308,7 @@ struct ResourceResponseData { , httpStatusText(WTFMove(httpStatusText)) , httpVersion(WTFMove(httpVersion)) , httpHeaderFields(WTFMove(httpHeaderFields)) @@ -8148,7 +7982,7 @@ index 95c24f85913c09bdf2e7b9e6c4e308d9528b06af..d6da8d829b0f40a9f234429aa97c5bd0 , networkLoadMetrics(WTFMove(networkLoadMetrics)) , source(source) , type(type) -@@ -323,6 +329,7 @@ struct ResourceResponseData { +@@ -325,6 +331,7 @@ struct ResourceResponseData { String httpStatusText; String httpVersion; HTTPHeaderMap httpHeaderFields; @@ -8157,10 +7991,10 @@ index 95c24f85913c09bdf2e7b9e6c4e308d9528b06af..d6da8d829b0f40a9f234429aa97c5bd0 ResourceResponseBase::Source source; ResourceResponseBase::Type type; diff --git a/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm b/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm -index cac3c4ba93f274637a93e0a20a4a0828c9c1bb46..e9f310f158015ed7a14ef2eb06d1d4d3f96d067d 100644 +index 52c078b497e11adc41e2e31a09ebf2f052b6f272..051b5fe3f42eb72ff478693b1d9a74b251332840 100644 --- a/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm +++ b/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm -@@ -493,6 +493,22 @@ bool NetworkStorageSession::setCookieFromDOM(const URL& firstParty, const SameSi +@@ -536,6 +536,22 @@ bool NetworkStorageSession::setCookieFromDOM(const URL& firstParty, const SameSi return false; } @@ -8294,7 +8128,7 @@ index 7567442a6bdccbe755b2cf5e3fa42265a065a9e1..4886cf0b5a6bc0b8a270d763ad481f5b { switch (cookieDatabase().acceptPolicy()) { diff --git a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp -index 09ab1320beacc41ae92399f3320aaf805d9d81d1..e1caf6e7ebd61151439a9c86350e57122784af0b 100644 +index 98285739dff7050e61611a23075599dcbe259d6a..b05dd64c53accd98dbb9e9e467aae3e07de7b974 100644 --- a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp +++ b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp @@ -424,6 +424,26 @@ void NetworkStorageSession::replaceCookies(const Vector& cookies) @@ -8325,7 +8159,7 @@ index 09ab1320beacc41ae92399f3320aaf805d9d81d1..e1caf6e7ebd61151439a9c86350e5712 { GUniquePtr targetCookie(cookie.toSoupCookie()); diff --git a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp -index 71c773f4532b6670c4f29496cc8c4bd3093304b1..5876dfa98bb9cdb78d0de807d4408ae661c3f288 100644 +index 9af57876ef4adddcf713392a3946efc30e75d3b7..956859daed43591ee52b20b2dfa6d381b812fbda 100644 --- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp +++ b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp @@ -40,6 +40,7 @@ @@ -8336,7 +8170,7 @@ index 71c773f4532b6670c4f29496cc8c4bd3093304b1..5876dfa98bb9cdb78d0de807d4408ae6 namespace WebCore { -@@ -690,7 +691,10 @@ template void getStringData(IDataObject* data, FORMATETC* format, Ve +@@ -691,7 +692,10 @@ template void getStringData(IDataObject* data, FORMATETC* format, Ve STGMEDIUM store; if (FAILED(data->GetData(format, &store))) return; @@ -8361,10 +8195,10 @@ index c3ffc7392c0b7fa099a7dd4e4be977cdee1c803c..9570dbb0f2c42ca38598a8898183c9b3 HGLOBAL createGlobalData(const String&); HGLOBAL createGlobalData(const Vector&); diff --git a/Source/WebCore/platform/win/DragDataWin.cpp b/Source/WebCore/platform/win/DragDataWin.cpp -index 0379437d84807e4a8d3846afac5ec8a70e743e70..1ae19e2b755e99c9f4c3e6d5dc0e4f8b6ebe8ab3 100644 +index 0379437d84807e4a8d3846afac5ec8a70e743e70..5b0461bf12535d4900ffaddc2a87826280505233 100644 --- a/Source/WebCore/platform/win/DragDataWin.cpp +++ b/Source/WebCore/platform/win/DragDataWin.cpp -@@ -40,7 +40,7 @@ +@@ -40,12 +40,13 @@ namespace WebCore { @@ -8373,14 +8207,12 @@ index 0379437d84807e4a8d3846afac5ec8a70e743e70..1ae19e2b755e99c9f4c3e6d5dc0e4f8b : m_clientPosition(clientPosition) , m_globalPosition(globalPosition) , m_platformDragData(0) -@@ -48,6 +48,7 @@ DragData::DragData(const DragDataMap& data, const IntPoint& clientPosition, cons + , m_draggingSourceOperationMask(sourceOperationMask) , m_applicationFlags(flags) ++ , m_dragDestinationActionMask(dragDestinationAction) , m_pageID(pageID) , m_dragDataMap(data) -+ , m_dragDestinationActionMask(dragDestinationAction) { - } - @@ -63,7 +64,7 @@ bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const || (filenamePolicy == ConvertFilenames && (m_dragDataMap.contains(filenameWFormat()->cfFormat) || m_dragDataMap.contains(filenameFormat()->cfFormat))); } @@ -8415,10 +8247,10 @@ index d450bf9d0fd1f0bf8f28db483ac9d3d60fa9d114..72a59403a0b5493aea4a8e28eb15eac2 OptionSet PlatformKeyboardEvent::currentStateOfModifierKeys() diff --git a/Source/WebCore/platform/win/PasteboardWin.cpp b/Source/WebCore/platform/win/PasteboardWin.cpp -index 03e5dc0b6ff099c281c61f05b29cf155b96922af..9b4694bc816e0e62a37c57e64729f183baca9080 100644 +index 8aab5ddd1dc749ecdd02ac59eb81f16294d67235..31cfdfb8dd2e174f39470421c59d9e520ddf84de 100644 --- a/Source/WebCore/platform/win/PasteboardWin.cpp +++ b/Source/WebCore/platform/win/PasteboardWin.cpp -@@ -1137,7 +1137,21 @@ void Pasteboard::writeCustomData(const Vector& data) +@@ -1142,7 +1142,21 @@ void Pasteboard::writeCustomData(const Vector& data) } clear(); @@ -8440,7 +8272,7 @@ index 03e5dc0b6ff099c281c61f05b29cf155b96922af..9b4694bc816e0e62a37c57e64729f183 if (::OpenClipboard(m_owner)) { const auto& customData = data.first(); customData.forEachPlatformStringOrBuffer([](auto& type, auto& stringOrBuffer) { -@@ -1176,4 +1190,25 @@ void Pasteboard::write(const Color&) +@@ -1181,4 +1195,25 @@ void Pasteboard::write(const Color&) { } @@ -8910,24 +8742,11 @@ index 0000000000000000000000000000000000000000..a76b583a1e65cd6999fab4784c22dd9c +}; + +} // namespace WebCore -diff --git a/Source/WebCore/rendering/AncestorSubgridIterator.cpp b/Source/WebCore/rendering/AncestorSubgridIterator.cpp -index 4613cfc6af155593459f8af9c2bf4211a01383b9..209542305a8454da2f80691ab7759b0f62b32604 100644 ---- a/Source/WebCore/rendering/AncestorSubgridIterator.cpp -+++ b/Source/WebCore/rendering/AncestorSubgridIterator.cpp -@@ -30,7 +30,7 @@ - - namespace WebCore { - --AncestorSubgridIterator::AncestorSubgridIterator() = default; -+AncestorSubgridIterator::AncestorSubgridIterator() { }; - - AncestorSubgridIterator::AncestorSubgridIterator(SingleThreadWeakPtr firstAncestorSubgrid, GridTrackSizingDirection direction) - : m_firstAncestorSubgrid(firstAncestorSubgrid) diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp -index 02afb718cfae6a4314ab704fbe6a70d88a530312..ed32870de0571317a6527d89a14a6a51b7acfd33 100644 +index 9d3de8e13762a270bc60d4201e8f35b62c908cbd..0e3eb8955cb8c751a600a0cce7690504899cbea8 100644 --- a/Source/WebCore/rendering/RenderTextControl.cpp +++ b/Source/WebCore/rendering/RenderTextControl.cpp -@@ -225,13 +225,13 @@ void RenderTextControl::layoutExcludedChildren(bool relayoutChildren) +@@ -223,13 +223,13 @@ void RenderTextControl::layoutExcludedChildren(bool relayoutChildren) } } @@ -8943,7 +8762,7 @@ index 02afb718cfae6a4314ab704fbe6a70d88a530312..ed32870de0571317a6527d89a14a6a51 { auto innerText = innerTextElement(); diff --git a/Source/WebCore/rendering/RenderTextControl.h b/Source/WebCore/rendering/RenderTextControl.h -index b55e0d2d78beb62a7efa08cf7d47e8a9ebad362d..352d12a72fa72479d70164ea130648d9c26ff05a 100644 +index 8ff886aec15c960e06408f638892579a6c3f4879..a5f8889818e456504c82a99994dcf4b21774b99d 100644 --- a/Source/WebCore/rendering/RenderTextControl.h +++ b/Source/WebCore/rendering/RenderTextControl.h @@ -37,9 +37,9 @@ public: @@ -8980,25 +8799,11 @@ index db95c8273bd0deb3f903a45d02fc07bbbd8ab305..bf88228b4c838b90d11d430cc9429d51 WorkerOrWorkletGlobalScope& m_globalScope; }; -diff --git a/Source/WebKit/InspectorGResources.cmake b/Source/WebKit/InspectorGResources.cmake -index b9c1f0ad55ef8ddf18e0314a6f4ad8b490e5b214..a1e3b60f8e74988b072eb8cbca201fd84a45b2bc 100644 ---- a/Source/WebKit/InspectorGResources.cmake -+++ b/Source/WebKit/InspectorGResources.cmake -@@ -13,4 +13,9 @@ macro(WEBKIT_BUILD_INSPECTOR_GRESOURCES _derived_sources_dir _output_file) - SOURCE_XML ${_derived_sources_dir}/InspectorGResourceBundle.xml - RESOURCE_DIRS ${_derived_sources_dir}/InspectorResources/WebInspectorUI - ) -+ -+ add_custom_target(${_output_file} -+ ALL -+ DEPENDS ${_derived_sources_dir}/${_output_file} -+ ) - endmacro() diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp -index 298c215460d4c52d8d232e960bec52c2d05a9071..9c903e398c05e451df9131eae1d9a828cf2e6088 100644 +index fe493f26a5a49b6ec9404105e8012291e3c37aab..9dbd5fcbac6d48fe92e5f7d9174192517e31a015 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp -@@ -97,6 +97,8 @@ +@@ -96,6 +96,8 @@ #if PLATFORM(COCOA) #include @@ -9007,7 +8812,7 @@ index 298c215460d4c52d8d232e960bec52c2d05a9071..9c903e398c05e451df9131eae1d9a828 #endif #if ENABLE(APPLE_PAY_REMOTE_UI) -@@ -1109,6 +1111,14 @@ void NetworkConnectionToWebProcess::clearPageSpecificData(PageIdentifier pageID) +@@ -1148,6 +1150,14 @@ void NetworkConnectionToWebProcess::clearPageSpecificData(PageIdentifier pageID) storageSession->clearPageSpecificDataForResourceLoadStatistics(pageID); } @@ -9023,10 +8828,10 @@ index 298c215460d4c52d8d232e960bec52c2d05a9071..9c903e398c05e451df9131eae1d9a828 { if (auto* storageSession = protectedNetworkProcess()->storageSession(m_sessionID)) diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h -index 99a6472171acdf8ebffa29a86d69f47d8ea55d64..a95eb97d93656e78bad1a1d3450d3563886fc485 100644 +index 7d2ad64026a920e5007965c2096d202ad611efa5..db7aa5bc9aa34ba43e5254b72d2d2bcf4eafeacc 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h -@@ -366,6 +366,8 @@ private: +@@ -380,6 +380,8 @@ private: void clearPageSpecificData(WebCore::PageIdentifier); @@ -9036,10 +8841,10 @@ index 99a6472171acdf8ebffa29a86d69f47d8ea55d64..a95eb97d93656e78bad1a1d3450d3563 void logUserInteraction(RegistrableDomain&&); diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in -index 9377d0c9381ec40342dc8bbe60e80781116b2d3c..b29b70264d0b5e9409e8467db75bc0a5a3febc5a 100644 +index 580195a8f0e1fc690ecab8903bca002496a8822f..ce9ec7f6f668d46f6a14889f081dfc485a56e215 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in -@@ -75,6 +75,8 @@ messages -> NetworkConnectionToWebProcess WantsDispatchMessage { +@@ -80,6 +80,8 @@ messages -> NetworkConnectionToWebProcess WantsDispatchMessage { ClearPageSpecificData(WebCore::PageIdentifier pageID); @@ -9049,10 +8854,10 @@ index 9377d0c9381ec40342dc8bbe60e80781116b2d3c..b29b70264d0b5e9409e8467db75bc0a5 LogUserInteraction(WebCore::RegistrableDomain domain) ResourceLoadStatisticsUpdated(Vector statistics) -> () diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.cpp b/Source/WebKit/NetworkProcess/NetworkProcess.cpp -index 12b9f1488877b94e520f83191cd15b09836e9666..f65093ab8653a2f5c05a1c5a69f0f2b83d679e07 100644 +index d0fd9b84a4bd5ba0e81fde94d5f2200cf664d278..3696082965d7b51ac5404f4411ed9d2fb1b30a7e 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkProcess.cpp -@@ -638,6 +638,12 @@ void NetworkProcess::registrableDomainsExemptFromWebsiteDataDeletion(PAL::Sessio +@@ -645,6 +645,12 @@ void NetworkProcess::registrableDomainsExemptFromWebsiteDataDeletion(PAL::Sessio completionHandler({ }); } @@ -9066,18 +8871,10 @@ index 12b9f1488877b94e520f83191cd15b09836e9666..f65093ab8653a2f5c05a1c5a69f0f2b8 { if (auto* session = networkSession(sessionID)) { diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.h b/Source/WebKit/NetworkProcess/NetworkProcess.h -index dbc90242cd84de5ef39b404e0b9262fcdf7cd371..82c91b9edb72f4f48676d0e458448981e346917a 100644 +index 2f73648e4ddbf622b5ed52e25cbd6835fa706048..d0f354db52d964f75cf20767d29549fa0bdfbff9 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkProcess.h -@@ -33,6 +33,7 @@ - #include "DownloadManager.h" - #include "NetworkContentRuleListManager.h" - #include "QuotaIncreaseRequestIdentifier.h" -+#include "StorageNamespaceIdentifier.h" - #include "UseDownloadPlaceholder.h" - #include "WebPageProxyIdentifier.h" - #include "WebResourceLoadStatisticsStore.h" -@@ -84,6 +85,7 @@ class SessionID; +@@ -84,6 +84,7 @@ class SessionID; namespace WebCore { class CertificateInfo; @@ -9085,7 +8882,7 @@ index dbc90242cd84de5ef39b404e0b9262fcdf7cd371..82c91b9edb72f4f48676d0e458448981 class CurlProxySettings; class ProtectionSpace; class NetworkStorageSession; -@@ -220,6 +222,9 @@ public: +@@ -227,6 +228,9 @@ public: void registrableDomainsWithLastAccessedTime(PAL::SessionID, CompletionHandler>)>&&); void registrableDomainsExemptFromWebsiteDataDeletion(PAL::SessionID, CompletionHandler)>&&); @@ -9096,10 +8893,10 @@ index dbc90242cd84de5ef39b404e0b9262fcdf7cd371..82c91b9edb72f4f48676d0e458448981 void clearUserInteraction(PAL::SessionID, RegistrableDomain&&, CompletionHandler&&); void deleteAndRestrictWebsiteDataForRegistrableDomains(PAL::SessionID, OptionSet, RegistrableDomainsToDeleteOrRestrictWebsiteDataFor&&, CompletionHandler&&)>&&); diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in -index aa95d1cc6e90fd24d3dad3ff1b8052de66fc23f2..b57b6d72cd1d9bf34dc347750e2d2fb9d0111389 100644 +index ef4f18038deef8bbed0d24507048050a19e6351a..b2961f2ac65cc44505e7ea6d191ab3b5ec8165db 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in -@@ -85,6 +85,8 @@ messages -> NetworkProcess : AuxiliaryProcess WantsAsyncDispatchMessage { +@@ -86,6 +86,8 @@ messages -> NetworkProcess : AuxiliaryProcess WantsAsyncDispatchMessage { SetInspectionForServiceWorkersAllowed(PAL::SessionID sessionID, bool inspectable) @@ -9109,10 +8906,10 @@ index aa95d1cc6e90fd24d3dad3ff1b8052de66fc23f2..b57b6d72cd1d9bf34dc347750e2d2fb9 ClearUserInteraction(PAL::SessionID sessionID, WebCore::RegistrableDomain resourceDomain) -> () DumpResourceLoadStatistics(PAL::SessionID sessionID) -> (String dumpedStatistics) diff --git a/Source/WebKit/NetworkProcess/NetworkSession.h b/Source/WebKit/NetworkProcess/NetworkSession.h -index 50b6499bcef54f3eeac6f3885e0e58783604100c..16b1fad0436fb307f524e3ae36e70043a3c6b168 100644 +index 53acfd4c7c13b7595a7be3f13f5edac01f82b891..319386e3c6a1f760d548385859c2f0410f2727a5 100644 --- a/Source/WebKit/NetworkProcess/NetworkSession.h +++ b/Source/WebKit/NetworkProcess/NetworkSession.h -@@ -202,6 +202,9 @@ public: +@@ -205,6 +205,9 @@ public: void lowMemoryHandler(WTF::Critical); @@ -9122,7 +8919,7 @@ index 50b6499bcef54f3eeac6f3885e0e58783604100c..16b1fad0436fb307f524e3ae36e70043 void removeSoftUpdateLoader(ServiceWorkerSoftUpdateLoader* loader) { m_softUpdateLoaders.remove(loader); } void addNavigationPreloaderTask(ServiceWorkerFetchTask&); ServiceWorkerFetchTask* navigationPreloaderTaskFromFetchIdentifier(WebCore::FetchIdentifier); -@@ -317,6 +320,7 @@ protected: +@@ -328,6 +331,7 @@ protected: bool m_privateClickMeasurementDebugModeEnabled { false }; std::optional m_ephemeralMeasurement; bool m_isRunningEphemeralMeasurementTest { false }; @@ -9131,10 +8928,10 @@ index 50b6499bcef54f3eeac6f3885e0e58783604100c..16b1fad0436fb307f524e3ae36e70043 HashSet> m_keptAliveLoads; diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm -index 70ba7cd36661a2500783052f04076888f92c0eea..8b26ac70f0daa99ba8800e5785d54e31457f17af 100644 +index 2a7bf5142aea077a0686c66d6fc0b2430be18c98..2640236a871e5a6455b32716d84711098802813b 100644 --- a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm +++ b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm -@@ -772,6 +772,8 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didRece +@@ -773,6 +773,8 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didRece if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { sessionCocoa->setClientAuditToken(challenge); @@ -9143,7 +8940,7 @@ index 70ba7cd36661a2500783052f04076888f92c0eea..8b26ac70f0daa99ba8800e5785d54e31 NSURLSessionTaskTransactionMetrics *metrics = task._incompleteTaskMetrics.transactionMetrics.lastObject; auto tlsVersion = (tls_protocol_version_t)metrics.negotiatedTLSProtocolVersion.unsignedShortValue; -@@ -1121,6 +1123,13 @@ - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)data +@@ -1124,6 +1126,13 @@ - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)data resourceResponse.setDeprecatedNetworkLoadMetrics(WebCore::copyTimingData(taskMetrics, networkDataTask->networkLoadMetrics())); @@ -9158,7 +8955,7 @@ index 70ba7cd36661a2500783052f04076888f92c0eea..8b26ac70f0daa99ba8800e5785d54e31 #if !LOG_DISABLED LOG(NetworkSession, "%llu didReceiveResponse completionHandler (%d)", taskIdentifier, policyAction); diff --git a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp -index 63ca8f8066acb3be4b4dc8350bcc712e535bdd38..3dc3657ac2dc8ab89f56acb0615dd571091821b4 100644 +index 1e1c7897c858ddd5a1c69a4d5942102f5649ef14..1d2a4835905018a39bc33488e9bc1450cb728179 100644 --- a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp @@ -80,10 +80,18 @@ NetworkDataTaskCurl::NetworkDataTaskCurl(NetworkSession& session, NetworkDataTas @@ -9229,16 +9026,16 @@ index 63ca8f8066acb3be4b4dc8350bcc712e535bdd38..3dc3657ac2dc8ab89f56acb0615dd571 void NetworkDataTaskCurl::invokeDidReceiveResponse() { didReceiveResponse(ResourceResponse(m_response), NegotiatedLegacyTLS::No, PrivateRelayed::No, std::nullopt, [this, protectedThis = Ref { *this }](PolicyAction policyAction) { -@@ -324,6 +363,8 @@ void NetworkDataTaskCurl::invokeDidReceiveResponse() - downloadPtr->didCreateDestination(m_pendingDownloadLocation); +@@ -323,6 +362,8 @@ void NetworkDataTaskCurl::invokeDidReceiveResponse() + download->didCreateDestination(m_pendingDownloadLocation); if (m_curlRequest) m_curlRequest->completeDidReceiveResponse(); + else if (firstRequest().url().protocolIsData()) -+ downloadDataURL(*downloadPtr); ++ downloadDataURL(download); break; } default: -@@ -412,6 +453,8 @@ void NetworkDataTaskCurl::willPerformHTTPRedirection() +@@ -411,6 +452,8 @@ void NetworkDataTaskCurl::willPerformHTTPRedirection() m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password()); m_curlRequest->setAuthenticationScheme(ProtectionSpace::AuthenticationScheme::HTTPBasic); } @@ -9289,7 +9086,7 @@ index 0f7c70e405d00416c9e5e58f9c56423a4cf3947c..b730722c5bdb3949bedc1a578089bb3e bool m_blockingCookies { false }; diff --git a/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp b/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp -index 486849ef6f550a0f3caab311abf5743c6d38e5af..afeaac63a18d9e71d3afead23b7da4fecfc27544 100644 +index 49685c872d0fb042a401612201a7448af6f1ac8b..e98efc1c2e7e5a85980c8d39afcb600a1f6c5d23 100644 --- a/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp @@ -68,7 +68,7 @@ void NetworkSessionCurl::clearAlternativeServices(WallTime) @@ -9302,7 +9099,7 @@ index 486849ef6f550a0f3caab311abf5743c6d38e5af..afeaac63a18d9e71d3afead23b7da4fe void NetworkSessionCurl::didReceiveChallenge(WebSocketTask& webSocketTask, WebCore::AuthenticationChallenge&& challenge, CompletionHandler&& challengeCompletionHandler) diff --git a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp -index 06a8233cbe44e7dfe1515498d511db39091f1acc..00818acd28155d526707967a01146d00199f4aa4 100644 +index 1853b717d021c5ec5c79abb61bec684460646a7a..625b921890a75c521bdf6fc3a5fd4bf3e9d74006 100644 --- a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp @@ -39,11 +39,12 @@ @@ -9325,10 +9122,10 @@ index 06a8233cbe44e7dfe1515498d511db39091f1acc..00818acd28155d526707967a01146d00 - m_streamID = m_scheduler.createStream(request.url(), *this, WebCore::CurlStream::ServerTrustEvaluation::Enable, localhostAlias); + m_streamID = m_scheduler.createStream(request.url(), ignoreCertificateErrors, *this, WebCore::CurlStream::ServerTrustEvaluation::Enable, localhostAlias); - m_channel->didSendHandshakeRequest(WebCore::ResourceRequest(m_request)); + channel.didSendHandshakeRequest(WebCore::ResourceRequest(m_request)); } -@@ -260,7 +261,7 @@ void WebSocketTask::tryServerTrustEvaluation(WebCore::AuthenticationChallenge&& +@@ -265,7 +266,7 @@ void WebSocketTask::tryServerTrustEvaluation(WebCore::AuthenticationChallenge&& if (networkSession() && networkSession()->networkProcess().localhostAliasesForTesting().contains(m_request.url().host())) localhostAlias = WebCore::CurlStream::LocalhostAlias::Enable; @@ -9338,19 +9135,19 @@ index 06a8233cbe44e7dfe1515498d511db39091f1acc..00818acd28155d526707967a01146d00 didFail(WTFMove(errorReason)); }); diff --git a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h -index 0072cb40252b35ab54d8693562ee66a4c7ef6f45..2a44ad16131c80ee74bbb79a110ef16be9ab0765 100644 +index 70c88bf553159e26e63c6dc735ae2bb4358df698..967b2c849206784efe3b0d9a2364cd3e7600b1f9 100644 --- a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h +++ b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h -@@ -59,7 +59,7 @@ struct SessionSet; - class WebSocketTask : public CanMakeWeakPtr, public WebCore::CurlStream::Client { +@@ -55,7 +55,7 @@ class WebSocketTask : public CanMakeWeakPtr, public CanMakeChecke WTF_MAKE_TZONE_ALLOCATED(WebSocketTask); + WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(WebSocketTask); public: - WebSocketTask(NetworkSocketChannel&, WebPageProxyIdentifier, const WebCore::ResourceRequest&, const String& protocol, const WebCore::ClientOrigin&); + WebSocketTask(NetworkSocketChannel&, WebPageProxyIdentifier, const WebCore::ResourceRequest&, const String& protocol, bool ignoreCertificateErrors, const WebCore::ClientOrigin&); virtual ~WebSocketTask(); void sendString(std::span, CompletionHandler&&); -@@ -112,6 +112,7 @@ private: +@@ -110,6 +110,7 @@ private: WebPageProxyIdentifier m_webProxyPageID; WebCore::ResourceRequest m_request; String m_protocol; @@ -9378,7 +9175,7 @@ index a6d86f1388e8cae7c3939d1ecffb2c46eb5054c5..9e11224335211908fe8bf14edc4c22e9 ;; Except deny access to new-style iOS Keychain folders which are UUIDs. (deny file-read* file-write* diff --git a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp -index 73b2b6b95706f735badf6235225a31926bfcca66..39cfe910a3cde500a41259be60ac2e6e32fdb82e 100644 +index d781f70f2c31ff5631773684893a40d738bd9856..6270cfd7707a190f123b9750a31162fbc64c3086 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp @@ -461,6 +461,8 @@ void NetworkDataTaskSoup::didSendRequest(GRefPtr&& inputStream) @@ -9438,23 +9235,11 @@ index 599c405513ee38c74da12c01dafc23c6ece86aa0..5af7dc9306d211a5cff1736013716b08 #endif } -diff --git a/Source/WebKit/Platform/IPC/MessageSender.h b/Source/WebKit/Platform/IPC/MessageSender.h -index 214f41901fa6648d281da7e1129ae888f0b2c510..30081fb3bd783ef8cbfee1dcea4ffe5f8786eedc 100644 ---- a/Source/WebKit/Platform/IPC/MessageSender.h -+++ b/Source/WebKit/Platform/IPC/MessageSender.h -@@ -27,6 +27,7 @@ - - #include - #include -+#include - - namespace IPC { - diff --git a/Source/WebKit/PlatformGTK.cmake b/Source/WebKit/PlatformGTK.cmake -index efbb4cdb0f382c1a917062c63727036e00723be1..8a9e53def5166e9a6afa983a1ed84634bb092ec0 100644 +index 945c0ce1def2b3ed580e2f497b2347a8b2cebbac..722b30d805b005229b38fe4ef2c53c06b8fb2f24 100644 --- a/Source/WebKit/PlatformGTK.cmake +++ b/Source/WebKit/PlatformGTK.cmake -@@ -329,6 +329,9 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES +@@ -328,6 +328,9 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES ${GSTREAMER_PBUTILS_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS} ${LIBSOUP_INCLUDE_DIRS} @@ -9464,7 +9249,7 @@ index efbb4cdb0f382c1a917062c63727036e00723be1..8a9e53def5166e9a6afa983a1ed84634 ) list(APPEND WebKit_INTERFACE_INCLUDE_DIRECTORIES -@@ -359,6 +362,9 @@ if (USE_LIBWEBRTC) +@@ -364,6 +367,9 @@ if (USE_LIBWEBRTC) list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES "${THIRDPARTY_DIR}/libwebrtc/Source/" "${THIRDPARTY_DIR}/libwebrtc/Source/webrtc" @@ -9474,7 +9259,7 @@ index efbb4cdb0f382c1a917062c63727036e00723be1..8a9e53def5166e9a6afa983a1ed84634 ) endif () -@@ -410,6 +416,12 @@ else () +@@ -415,6 +421,12 @@ else () set(WebKitGTK_ENUM_HEADER_TEMPLATE ${WEBKIT_DIR}/UIProcess/API/gtk/WebKitEnumTypesGtk3.h.in) endif () @@ -9488,7 +9273,7 @@ index efbb4cdb0f382c1a917062c63727036e00723be1..8a9e53def5166e9a6afa983a1ed84634 set(WebKitGTK_ENUM_GENERATION_HEADERS ${WebKitGTK_INSTALLED_HEADERS}) list(REMOVE_ITEM WebKitGTK_ENUM_GENERATION_HEADERS ${WebKitGTK_DERIVED_SOURCES_DIR}/webkit/WebKitEnumTypes.h) diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake -index e1d7d2a9e635c753459db079170ef5385dc1a637..28fbd58183e126f73a9f3ccbaa682ae3593f1e79 100644 +index 3c5bdcf25c6f9c0c86d0c4550d5dc7486f99d703..259fce0cf15b4263148f6f6da59161001875b465 100644 --- a/Source/WebKit/PlatformWPE.cmake +++ b/Source/WebKit/PlatformWPE.cmake @@ -117,6 +117,8 @@ list(APPEND WebKit_SERIALIZATION_IN_FILES @@ -9508,7 +9293,7 @@ index e1d7d2a9e635c753459db079170ef5385dc1a637..28fbd58183e126f73a9f3ccbaa682ae3 ) if (ENABLE_2022_GLIB_API) -@@ -432,7 +435,16 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES +@@ -430,7 +433,16 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES ${GIO_UNIX_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${LIBSOUP_INCLUDE_DIRS} @@ -9526,10 +9311,10 @@ index e1d7d2a9e635c753459db079170ef5385dc1a637..28fbd58183e126f73a9f3ccbaa682ae3 list(APPEND WebKit_LIBRARIES WPE::libwpe diff --git a/Source/WebKit/PlatformWin.cmake b/Source/WebKit/PlatformWin.cmake -index 7da9a409b65a577566f143a26a9717d4ba687a3c..711b5e1c4c82dfdf9ac6139a6de0785d29c1cc20 100644 +index e0e9b52c43ee0742f705159c1369f2938b9c4956..05fa7d93a721f200143e9d3ac45a75ce942afc88 100644 --- a/Source/WebKit/PlatformWin.cmake +++ b/Source/WebKit/PlatformWin.cmake -@@ -56,8 +56,13 @@ list(APPEND WebKit_SOURCES +@@ -54,8 +54,13 @@ list(APPEND WebKit_SOURCES UIProcess/WebsiteData/win/WebsiteDataStoreWin.cpp UIProcess/win/AutomationClientWin.cpp @@ -9543,7 +9328,7 @@ index 7da9a409b65a577566f143a26a9717d4ba687a3c..711b5e1c4c82dfdf9ac6139a6de0785d UIProcess/win/WebPageProxyWin.cpp UIProcess/win/WebPopupMenuProxyWin.cpp UIProcess/win/WebProcessPoolWin.cpp -@@ -73,6 +78,7 @@ list(APPEND WebKit_SOURCES +@@ -71,6 +76,7 @@ list(APPEND WebKit_SOURCES WebProcess/MediaCache/WebMediaKeyStorageManager.cpp WebProcess/WebCoreSupport/win/WebPopupMenuWin.cpp @@ -9551,7 +9336,7 @@ index 7da9a409b65a577566f143a26a9717d4ba687a3c..711b5e1c4c82dfdf9ac6139a6de0785d WebProcess/WebPage/AcceleratedSurface.cpp -@@ -121,8 +127,81 @@ list(APPEND WebKit_PUBLIC_FRAMEWORK_HEADERS +@@ -120,8 +126,81 @@ list(APPEND WebKit_PUBLIC_FRAMEWORK_HEADERS list(APPEND WebKit_PRIVATE_LIBRARIES comctl32 @@ -9633,26 +9418,27 @@ index 7da9a409b65a577566f143a26a9717d4ba687a3c..711b5e1c4c82dfdf9ac6139a6de0785d list(APPEND WebProcess_SOURCES WebProcess/EntryPoint/win/WebProcessMain.cpp -diff --git a/Source/WebKit/Shared/API/c/wpe/WebKit.h b/Source/WebKit/Shared/API/c/wpe/WebKit.h -index a9aa21f5589dec453db1713c8846e0d2e687f552..9b94469d078d92e4b9e0c8149122b19a4d3b5307 100644 ---- a/Source/WebKit/Shared/API/c/wpe/WebKit.h -+++ b/Source/WebKit/Shared/API/c/wpe/WebKit.h -@@ -76,6 +76,7 @@ - // From Source/WebKit/UIProcess/API/C - #include - #include -+#include - #include - #include - #include +diff --git a/Source/WebKit/Scripts/generate-unified-sources.sh b/Source/WebKit/Scripts/generate-unified-sources.sh +index 666b9f0669ad6e7d9050ec5b7a7d67ac533be363..d50f0eb91074b6263be5805fd89818a3573cf0ef 100755 +--- a/Source/WebKit/Scripts/generate-unified-sources.sh ++++ b/Source/WebKit/Scripts/generate-unified-sources.sh +@@ -18,7 +18,7 @@ if [ $# -eq 0 ]; then + echo "Using unified source list files: Sources.txt, SourcesCocoa.txt, Platform/Sources.txt, Platform/SourcesCocoa.txt" + fi + +-UnifiedSourceCppFileCount=137 ++UnifiedSourceCppFileCount=139 + UnifiedSourceCFileCount=0 + UnifiedSourceMmFileCount=80 + diff --git a/Source/WebKit/Shared/AuxiliaryProcess.h b/Source/WebKit/Shared/AuxiliaryProcess.h -index 33eb250f82068c481176be8e1ba6f9bc935f544a..519be7021eb53e3a6f18953ff004218e13f0819c 100644 +index 4510beb0b7403138abef4c9b5e892271fe8beaab..dae8f31ef187d7b086dd84d7e356839dc2811154 100644 --- a/Source/WebKit/Shared/AuxiliaryProcess.h +++ b/Source/WebKit/Shared/AuxiliaryProcess.h -@@ -214,6 +214,11 @@ struct AuxiliaryProcessInitializationParameters { - #if PLATFORM(COCOA) - SDKAlignedBehaviors clientSDKAlignedBehaviors; - #endif +@@ -212,6 +212,11 @@ struct AuxiliaryProcessInitializationParameters { + IPC::Connection::Identifier connectionIdentifier; + HashMap extraInitializationData; + WTF::AuxiliaryProcessType processType; +// Playwright begin +#if !PLATFORM(COCOA) + bool shouldEnableSharedArrayBuffer { false }; @@ -9661,18 +9447,6 @@ index 33eb250f82068c481176be8e1ba6f9bc935f544a..519be7021eb53e3a6f18953ff004218e }; } // namespace WebKit -diff --git a/Source/WebKit/Shared/Cocoa/CompletionHandlerCallChecker.h b/Source/WebKit/Shared/Cocoa/CompletionHandlerCallChecker.h -index b09b17a5bff38e3ba8d6bb53da9ef09d229bdb61..46aa1caa93402711a08f5980387a957f783038e5 100644 ---- a/Source/WebKit/Shared/Cocoa/CompletionHandlerCallChecker.h -+++ b/Source/WebKit/Shared/Cocoa/CompletionHandlerCallChecker.h -@@ -27,6 +27,7 @@ - - #import - #import -+#import - - namespace WebKit { - diff --git a/Source/WebKit/Shared/NativeWebKeyboardEvent.h b/Source/WebKit/Shared/NativeWebKeyboardEvent.h index c72c9733800b6f836c4d3ccb0b50d40c3ee83067..e2955ddebe388d886ca43d733dce0eb58256ce8b 100644 --- a/Source/WebKit/Shared/NativeWebKeyboardEvent.h @@ -9777,10 +9551,10 @@ index ea1eb9f00feaaecf73bdddc37c904e88f43bfa85..8a631e5293a11abd650958baad4e9678 #endif }; diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in -index 13f2e0158846e32155fc0ee9e9639f66d96e0f3f..3e8be3a130075a67c07fa192e788b24dab997480 100644 +index fda0fedd6538fa8d239775da0949d907f235be33..a8218678e5a0ffab6828529395bbd783b955b256 100644 --- a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in +++ b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in -@@ -2752,6 +2752,9 @@ class WebCore::AuthenticationChallenge { +@@ -2764,6 +2764,9 @@ class WebCore::AuthenticationChallenge { class WebCore::DragData { #if PLATFORM(COCOA) String pasteboardName(); @@ -9790,7 +9564,7 @@ index 13f2e0158846e32155fc0ee9e9639f66d96e0f3f..3e8be3a130075a67c07fa192e788b24d #endif WebCore::IntPoint clientPosition(); WebCore::IntPoint globalPosition(); -@@ -3311,6 +3314,7 @@ enum class WebCore::WasPrivateRelayed : bool; +@@ -3562,6 +3565,7 @@ enum class WebCore::WasPrivateRelayed : bool; String httpStatusText; String httpVersion; WebCore::HTTPHeaderMap httpHeaderFields; @@ -9799,10 +9573,10 @@ index 13f2e0158846e32155fc0ee9e9639f66d96e0f3f..3e8be3a130075a67c07fa192e788b24d WebCore::ResourceResponseBase::Source source; WebCore::ResourceResponseBase::Type type; diff --git a/Source/WebKit/Shared/WebKeyboardEvent.cpp b/Source/WebKit/Shared/WebKeyboardEvent.cpp -index b80bcb39473ecec86be5671f38698130bd9acbf3..d886cbac5f4c073e14e12f257fa920419ea0cf39 100644 +index 8040819bba9dcde87311aaafe7d8177d0e07281d..24972c0a357324d27910ae6ff1979d1c6b8bc758 100644 --- a/Source/WebKit/Shared/WebKeyboardEvent.cpp +++ b/Source/WebKit/Shared/WebKeyboardEvent.cpp -@@ -52,6 +52,24 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S +@@ -51,6 +51,24 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S ASSERT(isKeyboardEventType(type())); } @@ -9827,7 +9601,7 @@ index b80bcb39473ecec86be5671f38698130bd9acbf3..d886cbac5f4c073e14e12f257fa92041 #elif PLATFORM(GTK) WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional>&& preeditUnderlines, std::optional&& preeditSelectionRange, Vector&& commands, bool isAutoRepeat, bool isKeypad) -@@ -75,6 +93,24 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S +@@ -74,6 +92,24 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S ASSERT(isKeyboardEventType(type())); } @@ -9852,7 +9626,7 @@ index b80bcb39473ecec86be5671f38698130bd9acbf3..d886cbac5f4c073e14e12f257fa92041 #elif PLATFORM(IOS_FAMILY) WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, bool isAutoRepeat, bool isKeypad, bool isSystemKey) -@@ -138,6 +174,27 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S +@@ -137,6 +173,27 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S #endif @@ -9916,7 +9690,7 @@ index fd4722dd38df74f259d8add02025549022a0a205..e1c33f6d766707170935b3e77e81098c void setPosition(const WebCore::IntPoint& position) { m_position = position; } const WebCore::IntPoint& globalPosition() const { return m_globalPosition; } diff --git a/Source/WebKit/Shared/WebPageCreationParameters.h b/Source/WebKit/Shared/WebPageCreationParameters.h -index a75ea6985662cfb232a4910189191759a20f34b9..6e5fc673484ce3ca9750bb8a7dd56d6f704b7b66 100644 +index 8b5cedc5b433d8b7c1cdadf8206bd7b446ae7c21..9a8ac919d38ce51ffb1e0aeda9f23ce587736dd8 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.h +++ b/Source/WebKit/Shared/WebPageCreationParameters.h @@ -306,6 +306,8 @@ struct WebPageCreationParameters { @@ -9929,10 +9703,10 @@ index a75ea6985662cfb232a4910189191759a20f34b9..6e5fc673484ce3ca9750bb8a7dd56d6f bool allowsDeprecatedSynchronousXMLHttpRequestDuringUnload { false }; #endif diff --git a/Source/WebKit/Shared/WebPageCreationParameters.serialization.in b/Source/WebKit/Shared/WebPageCreationParameters.serialization.in -index 2c3fc666d67714ab966a9b991ed2eccc45cf1ff1..929ee387024355c40333ae7e12d7155688299e32 100644 +index bf9888a54cfe4fe5f2dee954b82fa9301498175b..85a2c43977be2751a61a9594c53270fb1bb26b4f 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.serialization.in +++ b/Source/WebKit/Shared/WebPageCreationParameters.serialization.in -@@ -230,6 +230,8 @@ enum class WebCore::UserInterfaceLayoutDirection : bool; +@@ -226,6 +226,8 @@ enum class WebCore::UserInterfaceLayoutDirection : bool; bool httpsUpgradeEnabled; @@ -9941,6 +9715,28 @@ index 2c3fc666d67714ab966a9b991ed2eccc45cf1ff1..929ee387024355c40333ae7e12d71556 #if PLATFORM(IOS) || PLATFORM(VISION) bool allowsDeprecatedSynchronousXMLHttpRequestDuringUnload; #endif +diff --git a/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp b/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp +index 40d482a1860598391363027e63b010b3ce32b014..e654ae5e7c54b788badd463b1f2b653160d0370e 100644 +--- a/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp ++++ b/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp +@@ -32,7 +32,7 @@ + + namespace WebKit { + +-#if ENABLE(DEVELOPER_MODE) ++#if TRUE + static String getExecutablePath() + { + CString executablePath = FileSystem::currentExecutablePath(); +@@ -44,7 +44,7 @@ static String getExecutablePath() + + static String findWebKitProcess(const char* processName) + { +-#if ENABLE(DEVELOPER_MODE) ++#if TRUE + static const char* execDirectory = g_getenv("WEBKIT_EXEC_PATH"); + if (execDirectory) { + String processPath = FileSystem::pathByAppendingComponent(FileSystem::stringFromFileSystemRepresentation(execDirectory), StringView::fromLatin1(processName)); diff --git a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp index 8d33ceb065fb3e90372b0c696779189d07838da0..6e3194c3e96e46bfa09f8d706324e6515df1e7f4 100644 --- a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp @@ -10012,10 +9808,10 @@ index 0000000000000000000000000000000000000000..f4f09d171ebf9774b3f8744751d220d3 + bool canSmartReplace() +} diff --git a/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp b/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp -index ce942ed6ce6bfda002e94c81633d56b2464c129d..0db4d7e6ab7f584b18d923f1ece6b498be1d463d 100644 +index f931d51a7b1818155729d5622038c442bba53cc0..d7c1ce87abca61fb5b72368376352ce93744a9a1 100644 --- a/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp +++ b/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp -@@ -44,6 +44,15 @@ +@@ -40,6 +40,15 @@ namespace WebKit { @@ -10031,8 +9827,8 @@ index ce942ed6ce6bfda002e94c81633d56b2464c129d..0db4d7e6ab7f584b18d923f1ece6b498 AuxiliaryProcessMainCommon::AuxiliaryProcessMainCommon() { #if ENABLE(BREAKPAD) -@@ -97,6 +106,10 @@ bool AuxiliaryProcessMainCommon::parseCommandLine(int argc, char** argv) - JSC::Config::configureForTesting(); +@@ -94,6 +103,10 @@ WTF_ALLOW_UNSAFE_BUFFER_USAGE_END + } #endif +// Playwright begin @@ -10043,13 +9839,13 @@ index ce942ed6ce6bfda002e94c81633d56b2464c129d..0db4d7e6ab7f584b18d923f1ece6b498 } diff --git a/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp b/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp -index 7fd5cbb0fec93a2f305a6d41f14946ec6dae778e..4332ec81e0d24928000483b3e554e385ee3b9ff1 100644 +index 9edb5fbcd103cd8d1b224dfd60ac88aabe9626d2..9ed392ae3809f8bda92a2765ffadc643f23fe856 100644 --- a/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp +++ b/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp @@ -41,6 +41,10 @@ bool AuxiliaryProcessMainCommon::parseCommandLine(int argc, char** argv) m_parameters.connectionIdentifier = IPC::Connection::Identifier { reinterpret_cast(parseIntegerAllowingTrailingJunk(StringView::fromLatin1(argv[++i])).value_or(0)) }; else if (!strcmp(argv[i], "-processIdentifier") && i + 1 < argc) - m_parameters.processIdentifier = LegacyNullableObjectIdentifier(parseIntegerAllowingTrailingJunk(StringView::fromLatin1(argv[++i])).value_or(0)); + m_parameters.processIdentifier = ObjectIdentifier(parseIntegerAllowingTrailingJunk(StringView::fromLatin1(argv[++i])).value_or(0)); +// Playwright begin + else if (!strcmp(argv[i], "-enable-shared-array-buffer")) + m_parameters.shouldEnableSharedArrayBuffer = true; @@ -10058,7 +9854,7 @@ index 7fd5cbb0fec93a2f305a6d41f14946ec6dae778e..4332ec81e0d24928000483b3e554e385 JSC::Config::configureForTesting(); else if (!strcmp(argv[i], "-disable-jit")) diff --git a/Source/WebKit/Shared/win/WebEventFactory.cpp b/Source/WebKit/Shared/win/WebEventFactory.cpp -index 4d418e2bd7f970bc5bfebceb88adb172e5eb8540..8a58380d830f9a8aec3b4240d9c8cf7e65eaccdc 100644 +index a1044685ff596361f14f418a1d1f0b133dee385a..2916a6f8e0c370b860ea45106c34d8dd82547f93 100644 --- a/Source/WebKit/Shared/win/WebEventFactory.cpp +++ b/Source/WebKit/Shared/win/WebEventFactory.cpp @@ -484,7 +484,7 @@ WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(HWND hwnd, UINT message @@ -10071,10 +9867,10 @@ index 4d418e2bd7f970bc5bfebceb88adb172e5eb8540..8a58380d830f9a8aec3b4240d9c8cf7e #endif // ENABLE(TOUCH_EVENTS) diff --git a/Source/WebKit/Sources.txt b/Source/WebKit/Sources.txt -index e1914a5393ae2e099fd9fc70d46cb4f1ad2a9aee..3918547200acc80c76a4c55136d28295c60a4217 100644 +index 63be8e6480621c508443ba589342034a8cd64523..57b13efa8198ffa203510642b2db8aae526f5030 100644 --- a/Source/WebKit/Sources.txt +++ b/Source/WebKit/Sources.txt -@@ -385,6 +385,7 @@ Shared/XR/XRDeviceProxy.cpp +@@ -384,6 +384,7 @@ Shared/XR/XRDeviceProxy.cpp UIProcess/AuxiliaryProcessProxy.cpp UIProcess/BackgroundProcessResponsivenessTimer.cpp UIProcess/BrowsingContextGroup.cpp @@ -10082,7 +9878,7 @@ index e1914a5393ae2e099fd9fc70d46cb4f1ad2a9aee..3918547200acc80c76a4c55136d28295 UIProcess/DeviceIdHashSaltStorage.cpp UIProcess/DisplayLink.cpp UIProcess/DisplayLinkProcessProxyClient.cpp -@@ -394,16 +395,20 @@ UIProcess/FrameLoadState.cpp +@@ -393,16 +394,20 @@ UIProcess/FrameLoadState.cpp UIProcess/FrameProcess.cpp UIProcess/GeolocationPermissionRequestManagerProxy.cpp UIProcess/GeolocationPermissionRequestProxy.cpp @@ -10103,7 +9899,7 @@ index e1914a5393ae2e099fd9fc70d46cb4f1ad2a9aee..3918547200acc80c76a4c55136d28295 UIProcess/RemotePageDrawingAreaProxy.cpp UIProcess/RemotePageProxy.cpp UIProcess/ResponsivenessTimer.cpp -@@ -445,6 +450,8 @@ UIProcess/WebOpenPanelResultListenerProxy.cpp +@@ -444,6 +449,8 @@ UIProcess/WebOpenPanelResultListenerProxy.cpp UIProcess/WebPageDiagnosticLoggingClient.cpp UIProcess/WebPageGroup.cpp UIProcess/WebPageInjectedBundleClient.cpp @@ -10125,10 +9921,10 @@ index e1914a5393ae2e099fd9fc70d46cb4f1ad2a9aee..3918547200acc80c76a4c55136d28295 UIProcess/Media/AudioSessionRoutingArbitratorProxy.cpp UIProcess/Media/MediaUsageManager.cpp diff --git a/Source/WebKit/SourcesCocoa.txt b/Source/WebKit/SourcesCocoa.txt -index 747fe6c2c1f8d8058ad4ecf3a671f80f5da60d78..1767179349cda6228a3dc7fc25e64b969e9a9668 100644 +index 703fed777c597c14e0794270747c771627118460..a521863925b7392e1172f62d818bde3e4d66850c 100644 --- a/Source/WebKit/SourcesCocoa.txt +++ b/Source/WebKit/SourcesCocoa.txt -@@ -267,6 +267,7 @@ UIProcess/API/Cocoa/_WKArchiveExclusionRule.mm +@@ -270,6 +270,7 @@ UIProcess/API/Cocoa/_WKArchiveExclusionRule.mm UIProcess/API/Cocoa/_WKAttachment.mm UIProcess/API/Cocoa/_WKAutomationSession.mm UIProcess/API/Cocoa/_WKAutomationSessionConfiguration.mm @@ -10136,7 +9932,7 @@ index 747fe6c2c1f8d8058ad4ecf3a671f80f5da60d78..1767179349cda6228a3dc7fc25e64b96 UIProcess/API/Cocoa/_WKContentRuleListAction.mm UIProcess/API/Cocoa/_WKContextMenuElementInfo.mm UIProcess/API/Cocoa/_WKCustomHeaderFields.mm @no-unify -@@ -457,6 +458,7 @@ UIProcess/Inspector/ios/WKInspectorHighlightView.mm +@@ -464,6 +465,7 @@ UIProcess/Inspector/ios/WKInspectorHighlightView.mm UIProcess/Inspector/ios/WKInspectorNodeSearchGestureRecognizer.mm UIProcess/Inspector/mac/RemoteWebInspectorUIProxyMac.mm @@ -10145,10 +9941,10 @@ index 747fe6c2c1f8d8058ad4ecf3a671f80f5da60d78..1767179349cda6228a3dc7fc25e64b96 UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm UIProcess/Inspector/mac/WKInspectorViewController.mm diff --git a/Source/WebKit/SourcesGTK.txt b/Source/WebKit/SourcesGTK.txt -index e193244e152b0c7ca76ecfd3b761412e80e0019a..e557aa325075828ccb94cc2cd62d10751847c4ef 100644 +index 39c4934ff42c3854a5c4acf379812d3f8d55832f..0fcdeea00c863c6b72469b3f4cd8561f0d7113c5 100644 --- a/Source/WebKit/SourcesGTK.txt +++ b/Source/WebKit/SourcesGTK.txt -@@ -130,6 +130,7 @@ UIProcess/API/glib/WebKitAutomationSession.cpp @no-unify +@@ -122,6 +122,7 @@ UIProcess/API/glib/WebKitAutomationSession.cpp @no-unify UIProcess/API/glib/WebKitBackForwardList.cpp @no-unify UIProcess/API/glib/WebKitBackForwardListItem.cpp @no-unify UIProcess/API/glib/WebKitClipboardPermissionRequest.cpp @no-unify @@ -10156,15 +9952,15 @@ index e193244e152b0c7ca76ecfd3b761412e80e0019a..e557aa325075828ccb94cc2cd62d1075 UIProcess/API/glib/WebKitContextMenuClient.cpp @no-unify UIProcess/API/glib/WebKitCookieManager.cpp @no-unify UIProcess/API/glib/WebKitCredential.cpp @no-unify -@@ -259,6 +260,7 @@ UIProcess/glib/DisplayVBlankMonitor.cpp +@@ -252,6 +253,7 @@ UIProcess/glib/DisplayVBlankMonitor.cpp UIProcess/glib/DisplayVBlankMonitorDRM.cpp UIProcess/glib/DisplayVBlankMonitorTimer.cpp UIProcess/glib/FenceMonitor.cpp +UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp UIProcess/glib/ScreenManager.cpp - UIProcess/glib/SystemSettingsManager.cpp + UIProcess/glib/SystemSettingsManagerProxy.cpp UIProcess/glib/WebPageProxyGLib.cpp -@@ -277,6 +279,7 @@ UIProcess/gtk/DisplayX11.cpp @no-unify +@@ -270,6 +272,7 @@ UIProcess/gtk/DisplayX11.cpp @no-unify UIProcess/gtk/DisplayWayland.cpp @no-unify UIProcess/gtk/WebDateTimePickerGtk.cpp UIProcess/gtk/HardwareAccelerationManager.cpp @@ -10172,7 +9968,7 @@ index e193244e152b0c7ca76ecfd3b761412e80e0019a..e557aa325075828ccb94cc2cd62d1075 UIProcess/gtk/KeyBindingTranslator.cpp UIProcess/gtk/PointerLockManager.cpp @no-unify UIProcess/gtk/PointerLockManagerWayland.cpp @no-unify -@@ -290,6 +293,8 @@ UIProcess/gtk/ViewGestureControllerGtk.cpp +@@ -283,6 +286,8 @@ UIProcess/gtk/ViewGestureControllerGtk.cpp UIProcess/gtk/WebColorPickerGtk.cpp UIProcess/gtk/WebContextMenuProxyGtk.cpp UIProcess/gtk/WebDataListSuggestionsDropdownGtk.cpp @@ -10182,10 +9978,10 @@ index e193244e152b0c7ca76ecfd3b761412e80e0019a..e557aa325075828ccb94cc2cd62d1075 UIProcess/gtk/WebPasteboardProxyGtk.cpp UIProcess/gtk/WebPopupMenuProxyGtk.cpp diff --git a/Source/WebKit/SourcesWPE.txt b/Source/WebKit/SourcesWPE.txt -index a5952c5ba4380b03bc418ce33332ad3d9a3dc372..ca966a925647e37cc00f74b704957e270600a4e2 100644 +index 3eaaa65a91fb381bd7366e36c147e0cba64358d4..645f0c98e248de12731c2bdf693eaef614535b3f 100644 --- a/Source/WebKit/SourcesWPE.txt +++ b/Source/WebKit/SourcesWPE.txt -@@ -132,6 +132,7 @@ UIProcess/API/glib/WebKitAuthenticationRequest.cpp @no-unify +@@ -124,6 +124,7 @@ UIProcess/API/glib/WebKitAuthenticationRequest.cpp @no-unify UIProcess/API/glib/WebKitAutomationSession.cpp @no-unify UIProcess/API/glib/WebKitBackForwardList.cpp @no-unify UIProcess/API/glib/WebKitBackForwardListItem.cpp @no-unify @@ -10193,7 +9989,7 @@ index a5952c5ba4380b03bc418ce33332ad3d9a3dc372..ca966a925647e37cc00f74b704957e27 UIProcess/API/glib/WebKitContextMenuClient.cpp @no-unify UIProcess/API/glib/WebKitCookieManager.cpp @no-unify UIProcess/API/glib/WebKitCredential.cpp @no-unify -@@ -165,6 +166,7 @@ UIProcess/API/glib/WebKitOptionMenu.cpp @no-unify +@@ -157,6 +158,7 @@ UIProcess/API/glib/WebKitOptionMenu.cpp @no-unify UIProcess/API/glib/WebKitOptionMenuItem.cpp @no-unify UIProcess/API/glib/WebKitPermissionRequest.cpp @no-unify UIProcess/API/glib/WebKitPermissionStateQuery.cpp @no-unify @@ -10201,7 +9997,7 @@ index a5952c5ba4380b03bc418ce33332ad3d9a3dc372..ca966a925647e37cc00f74b704957e27 UIProcess/API/glib/WebKitPolicyDecision.cpp @no-unify UIProcess/API/glib/WebKitPrivate.cpp @no-unify UIProcess/API/glib/WebKitProtocolHandler.cpp @no-unify -@@ -201,6 +203,7 @@ UIProcess/API/soup/HTTPCookieStoreSoup.cpp +@@ -193,6 +195,7 @@ UIProcess/API/soup/HTTPCookieStoreSoup.cpp UIProcess/API/wpe/InputMethodFilterWPE.cpp @no-unify UIProcess/API/wpe/PageClientImpl.cpp @no-unify UIProcess/API/wpe/WebKitColor.cpp @no-unify @@ -10209,20 +10005,21 @@ index a5952c5ba4380b03bc418ce33332ad3d9a3dc372..ca966a925647e37cc00f74b704957e27 UIProcess/API/wpe/WebKitInputMethodContextWPE.cpp @no-unify UIProcess/API/wpe/WebKitInputMethodContextImplWPE.cpp @no-unify UIProcess/API/wpe/WebKitPopupMenu.cpp @no-unify -@@ -229,6 +232,7 @@ UIProcess/glib/DisplayVBlankMonitor.cpp +@@ -221,6 +224,7 @@ UIProcess/glib/DisplayVBlankMonitor.cpp UIProcess/glib/DisplayVBlankMonitorDRM.cpp UIProcess/glib/DisplayVBlankMonitorTimer.cpp UIProcess/glib/FenceMonitor.cpp +UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp UIProcess/glib/ScreenManager.cpp - UIProcess/glib/SystemSettingsManager.cpp + UIProcess/glib/SystemSettingsManagerProxy.cpp UIProcess/glib/WebPageProxyGLib.cpp -@@ -262,7 +266,12 @@ UIProcess/linux/MemoryPressureMonitor.cpp +@@ -254,8 +258,13 @@ UIProcess/linux/MemoryPressureMonitor.cpp UIProcess/soup/WebProcessPoolSoup.cpp UIProcess/wpe/AcceleratedBackingStoreDMABuf.cpp +UIProcess/wpe/InspectorTargetProxyWPE.cpp UIProcess/wpe/ScreenManagerWPE.cpp + UIProcess/wpe/SystemSettingsManagerProxyWPE.cpp +UIProcess/wpe/WebColorPickerWPE.cpp +UIProcess/wpe/WebDateTimePickerWPE.cpp +UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp @@ -10230,7 +10027,7 @@ index a5952c5ba4380b03bc418ce33332ad3d9a3dc372..ca966a925647e37cc00f74b704957e27 UIProcess/wpe/WebPageProxyWPE.cpp UIProcess/wpe/WebPreferencesWPE.cpp -@@ -289,6 +298,8 @@ WebProcess/WebCoreSupport/glib/WebEditorClientGLib.cpp +@@ -282,6 +291,8 @@ WebProcess/WebCoreSupport/glib/WebEditorClientGLib.cpp WebProcess/WebCoreSupport/soup/WebFrameNetworkingContext.cpp @@ -10239,8 +10036,47 @@ index a5952c5ba4380b03bc418ce33332ad3d9a3dc372..ca966a925647e37cc00f74b704957e27 WebProcess/WebCoreSupport/wpe/WebEditorClientWPE.cpp WebProcess/WebPage/AcceleratedSurface.cpp +diff --git a/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp b/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp +index bbd1b64631ed858686e118c94a5b44ef2bacc3f8..491e888db9e696ac65528ebd05a38224d9140b2f 100644 +--- a/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp ++++ b/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp +@@ -255,6 +255,11 @@ WebPageProxy* PageConfiguration::relatedPage() const + return m_data.relatedPage.get(); + } + ++WebKit::WebPageProxy* PageConfiguration::openerPageForInspector() const ++{ ++ return m_data.openerPageForInspector.get(); ++} ++ + WebPageProxy* PageConfiguration::pageToCloneSessionStorageFrom() const + { + return m_data.pageToCloneSessionStorageFrom.get(); +diff --git a/Source/WebKit/UIProcess/API/APIPageConfiguration.h b/Source/WebKit/UIProcess/API/APIPageConfiguration.h +index d4cc6c31b1cb6483cd1ac5d90762c4a2ad7c905a..2322900ab0c068d28f975bef27dac02b4469aef0 100644 +--- a/Source/WebKit/UIProcess/API/APIPageConfiguration.h ++++ b/Source/WebKit/UIProcess/API/APIPageConfiguration.h +@@ -156,6 +156,10 @@ public: + WebKit::WebPageProxy* relatedPage() const; + void setRelatedPage(WeakPtr&& relatedPage) { m_data.relatedPage = WTFMove(relatedPage); } + ++ // This is similar to relatedPage(), but it is also set for noopener links. ++ WebKit::WebPageProxy* openerPageForInspector() const; ++ void setOpenerPageForInspector(WeakPtr&& openerPageForInspector) { m_data.openerPageForInspector = WTFMove(openerPageForInspector); } ++ + WebKit::WebPageProxy* pageToCloneSessionStorageFrom() const; + void setPageToCloneSessionStorageFrom(WeakPtr&&); + +@@ -507,6 +511,7 @@ private: + #endif + RefPtr pageGroup; + WeakPtr relatedPage; ++ WeakPtr openerPageForInspector; + std::optional openerInfo; + WebCore::Site openedSite; + WTF::String openedMainFrameName; diff --git a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp -index d561c07ae53a60c6503a355ed620bc289a2220ae..b950ac5190d8d05c66718c545c76d53d45cfff9d 100644 +index e256b905bf9727aa7c8a48012237a6a6bc9acdbc..4e855c441af6f235f0fd8dfdd57b9bd6e4646492 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp @@ -52,6 +52,10 @@ Ref ProcessPoolConfiguration::copy() @@ -10255,7 +10091,7 @@ index d561c07ae53a60c6503a355ed620bc289a2220ae..b950ac5190d8d05c66718c545c76d53d copy->m_shouldTakeUIBackgroundAssertion = this->m_shouldTakeUIBackgroundAssertion; copy->m_shouldCaptureDisplayInUIProcess = this->m_shouldCaptureDisplayInUIProcess; diff --git a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h -index 32ef9bd308e520f5ac7173639c8b23ea91cde037..7a80553c2d91b9236f563fa1b76aa8a50b8545ba 100644 +index d2e8261c6db000aa41697b3bb50e2bea149edcdf..500c38b81d6804f64ff891e32b2c72ed98c9a629 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h @@ -96,6 +96,16 @@ public: @@ -10275,7 +10111,7 @@ index 32ef9bd308e520f5ac7173639c8b23ea91cde037..7a80553c2d91b9236f563fa1b76aa8a5 bool alwaysRunsAtBackgroundPriority() const { return m_alwaysRunsAtBackgroundPriority; } void setAlwaysRunsAtBackgroundPriority(bool alwaysRunsAtBackgroundPriority) { m_alwaysRunsAtBackgroundPriority = alwaysRunsAtBackgroundPriority; } -@@ -173,6 +183,10 @@ private: +@@ -178,6 +188,10 @@ private: bool m_ignoreSynchronousMessagingTimeoutsForTesting { false }; bool m_attrStyleEnabled { false }; bool m_shouldThrowExceptionForGlobalConstantRedeclaration { true }; @@ -10286,24 +10122,11 @@ index 32ef9bd308e520f5ac7173639c8b23ea91cde037..7a80553c2d91b9236f563fa1b76aa8a5 bool m_alwaysRunsAtBackgroundPriority { false }; bool m_shouldTakeUIBackgroundAssertion { true }; bool m_shouldCaptureDisplayInUIProcess { DEFAULT_CAPTURE_DISPLAY_IN_UI_PROCESS }; -diff --git a/Source/WebKit/UIProcess/API/APITargetedElementRequest.h b/Source/WebKit/UIProcess/API/APITargetedElementRequest.h -index 47e2ab76c6dc7ed92cd953f1462e6f4bd149e1d7..e70efd325dd229a207e1790cbf75954189ee87f6 100644 ---- a/Source/WebKit/UIProcess/API/APITargetedElementRequest.h -+++ b/Source/WebKit/UIProcess/API/APITargetedElementRequest.h -@@ -34,7 +34,7 @@ class WebPageProxy; - - namespace API { - --class TargetedElementRequest final : public ObjectImpl { -+class TargetedElementRequest final : public ObjectImpl { - public: - bool shouldIgnorePointerEventsNone() const { return m_request.shouldIgnorePointerEventsNone; } - void setShouldIgnorePointerEventsNone(bool value) { m_request.shouldIgnorePointerEventsNone = value; } diff --git a/Source/WebKit/UIProcess/API/APIUIClient.h b/Source/WebKit/UIProcess/API/APIUIClient.h -index 6c81074a5b918563a68a549b21be1c970a395643..0a9e1809f65ef749870c17d61e426e222af5463a 100644 +index 2972dde456001f5443142513711549297eff9b10..a71d47c77a1167863232f2e7d76381b3e87c4af3 100644 --- a/Source/WebKit/UIProcess/API/APIUIClient.h +++ b/Source/WebKit/UIProcess/API/APIUIClient.h -@@ -116,6 +116,7 @@ public: +@@ -115,6 +115,7 @@ public: virtual void runJavaScriptAlert(WebKit::WebPageProxy&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, Function&& completionHandler) { completionHandler(); } virtual void runJavaScriptConfirm(WebKit::WebPageProxy&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, Function&& completionHandler) { completionHandler(false); } virtual void runJavaScriptPrompt(WebKit::WebPageProxy&, const WTF::String&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, Function&& completionHandler) { completionHandler(WTF::String()); } @@ -10355,10 +10178,10 @@ index 026121d114c5fcad84c1396be8d692625beaa3bd..edd6e5cae033124c589959a42522fde0 } #endif diff --git a/Source/WebKit/UIProcess/API/C/WKPage.cpp b/Source/WebKit/UIProcess/API/C/WKPage.cpp -index 01fa2b32627f99540d82009dad97b6dbe921b59f..c5eaffd5f2496215dc4d45bf415bf41d3e216901 100644 +index bae7c5eb3879237a34a1abb249bf312822d59569..f905369dec97083ce4d4d60b838a63e56be36d77 100644 --- a/Source/WebKit/UIProcess/API/C/WKPage.cpp +++ b/Source/WebKit/UIProcess/API/C/WKPage.cpp -@@ -1795,6 +1795,13 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient +@@ -1801,6 +1801,13 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient completionHandler(String()); } @@ -10372,7 +10195,7 @@ index 01fa2b32627f99540d82009dad97b6dbe921b59f..c5eaffd5f2496215dc4d45bf415bf41d void setStatusText(WebPageProxy* page, const String& text) final { if (!m_client.setStatusText) -@@ -1824,6 +1831,8 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient +@@ -1830,6 +1837,8 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient { if (!m_client.didNotHandleKeyEvent) return; @@ -10442,10 +10265,10 @@ index 1484f064ec89ee8c25c35df9f0a4462896699415..0622f4d5fc9144b9059395d9d0730a4a // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm b/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm -index 26c2e39dbc49f9435a94ae4825e2ac5def1b061f..3bdf9f44707a0edc4c82a0f77a943df772e83828 100644 +index 93882c7e4c9873fce79af428ceaa73a4eca851cb..9d6f85a1ee633bdd6589fe9fae74d6f9ebff6e08 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm -@@ -702,6 +702,16 @@ - (void)_setMediaCaptureRequiresSecureConnection:(BOOL)requiresSecureConnection +@@ -712,6 +712,16 @@ - (void)_setMediaCaptureRequiresSecureConnection:(BOOL)requiresSecureConnection _preferences->setMediaCaptureRequiresSecureConnection(requiresSecureConnection); } @@ -10463,7 +10286,7 @@ index 26c2e39dbc49f9435a94ae4825e2ac5def1b061f..3bdf9f44707a0edc4c82a0f77a943df7 { return _preferences->inactiveMediaCaptureStreamRepromptIntervalInMinutes(); diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h b/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h -index 39065a0262f7c1a4ce35ba7373105df0b5ef17ee..fbde5990b2d881b2aec01dd99482bbb77f74e7b4 100644 +index 31de8ef3d986a5c391e1fb045268e95d5eefaf11..690cb85ab84d7ad2818ba4c362c8f0f25e25c1e1 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h @@ -119,6 +119,7 @@ typedef NS_ENUM(NSInteger, _WKPitchCorrectionAlgorithm) { @@ -10475,7 +10298,7 @@ index 39065a0262f7c1a4ce35ba7373105df0b5ef17ee..fbde5990b2d881b2aec01dd99482bbb7 @property (nonatomic, setter=_setICECandidateFilteringEnabled:) BOOL _iceCandidateFilteringEnabled WK_API_AVAILABLE(macos(10.13.4), ios(11.3)); @property (nonatomic, setter=_setInactiveMediaCaptureStreamRepromptIntervalInMinutes:) double _inactiveMediaCaptureStreamRepromptIntervalInMinutes WK_API_AVAILABLE(macos(10.13.4), ios(11.3)); diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h -index ca205ac38f92e95c24830d30657d093afd22f02b..aeaf6335ab9fc0590cd723e0c585677a014c4549 100644 +index ef512c7ba09298b2291d0248988574163ff2e7c8..d42e7f9f7b66840b68e61ce46b4bbd6254518ef7 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h @@ -149,6 +149,12 @@ WK_SWIFT_UI_ACTOR @@ -10492,18 +10315,10 @@ index ca205ac38f92e95c24830d30657d093afd22f02b..aeaf6335ab9fc0590cd723e0c585677a /*! @abstract A delegate to request permission for microphone audio and camera video access. @param webView The web view invoking the delegate method. diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h -index eff4cf557033561ab20762d93a58c2d71f5505f0..2fd5a2515c54d9edcab48fa3d993298fa3969648 100644 +index eff4cf557033561ab20762d93a58c2d71f5505f0..9418e2c51e50190dee2b5d7c854eacea8c5a4b76 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h -@@ -24,7 +24,6 @@ - */ - - #import -- - #import - - #if __has_include() -@@ -126,6 +125,8 @@ WK_CLASS_AVAILABLE(macos(10.11), ios(9.0)) +@@ -126,6 +126,8 @@ WK_CLASS_AVAILABLE(macos(10.11), ios(9.0)) #endif #endif @@ -10513,7 +10328,7 @@ index eff4cf557033561ab20762d93a58c2d71f5505f0..2fd5a2515c54d9edcab48fa3d993298f NS_ASSUME_NONNULL_END diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm -index 211037030a86db642e99c3881488897cd2d8caa9..eb6fb610dd5db0a10f1d121f0d9519943b9d9c0b 100644 +index 29f1855ec5009fecf05e3c3fda2d38845973c085..279b05f40b2d446bb7bedbcab4239e2f72656cd2 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm @@ -55,6 +55,7 @@ @@ -10524,7 +10339,7 @@ index 211037030a86db642e99c3881488897cd2d8caa9..eb6fb610dd5db0a10f1d121f0d951994 #import #import #import -@@ -489,6 +490,11 @@ - (void)removeDataOfTypes:(NSSet *)dataTypes modifiedSince:(NSDate *)date comple +@@ -496,6 +497,11 @@ - (void)removeDataOfTypes:(NSSet *)dataTypes modifiedSince:(NSDate *)date comple }); } @@ -10664,7 +10479,7 @@ index 0000000000000000000000000000000000000000..69eb9c6aa30beb8ea21a0ef647e46304 +} +@end diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h -index 9eadc5f1a8c9b002ab96727a1fb472403a21cf24..f3ceaaa8a23690b77e01aed1ed532e3afccd866c 100644 +index 426c7cbc897e22fd2e962dd3744959975d6ae6a0..f7a52359d7d42f970ef424b6c702b0ec1121a902 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h @@ -67,6 +67,7 @@ WK_CLASS_AVAILABLE(macos(10.10), ios(8.0)) @@ -10676,7 +10491,7 @@ index 9eadc5f1a8c9b002ab96727a1fb472403a21cf24..f3ceaaa8a23690b77e01aed1ed532e3a @property (nonatomic) BOOL processSwapsOnNavigationWithinSameNonHTTPFamilyProtocol WK_API_AVAILABLE(macos(12.0), ios(15.0)); @property (nonatomic) BOOL prewarmsProcessesAutomatically WK_API_AVAILABLE(macos(10.14.4), ios(12.2)); diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm -index df71be1e30c4a13fe9565d309c7bbfb82e049d06..8424a471e7841d300174aa54143578f8d18ad15f 100644 +index 38b516d32edc4038508c664e0c4dc804cd477787..891dd8b2451ab771e451ea8ef74906d364e76007 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm @@ -241,6 +241,16 @@ - (BOOL)processSwapsOnNavigation @@ -10696,18 +10511,6 @@ index df71be1e30c4a13fe9565d309c7bbfb82e049d06..8424a471e7841d300174aa54143578f8 - (void)setPrewarmsProcessesAutomatically:(BOOL)prewarms { _processPoolConfiguration->setIsAutomaticProcessWarmingEnabled(prewarms); -diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm -index 041fc95fcabaa12ba65da4e8d3ee3e9253b8dff8..4506f3208b8a338fc1bcdae6e9f227f9434b8bda 100644 ---- a/Source/WebKit/UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm -+++ b/Source/WebKit/UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm -@@ -24,6 +24,7 @@ - */ - - #import "config.h" -+#import "WKWebViewPrivate.h" - #import "_WKRemoteWebInspectorViewControllerInternal.h" - - #if PLATFORM(MAC) diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h b/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h index 4974e14214e2bb3e982325b885bab33e54f83998..cacdf8c71fab248d38d2faf03f7affdcfed1ef62 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h @@ -10720,18 +10523,32 @@ index 4974e14214e2bb3e982325b885bab33e54f83998..cacdf8c71fab248d38d2faf03f7affdc typedef NS_ENUM(NSInteger, _WKUserStyleLevel) { _WKUserStyleUserLevel, -diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.mm -index 8f7d300c449fd3323f3a47630a5b87835e7b2350..8b2b098f0bc8d9ad27654c33f616c0b73330573c 100644 ---- a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.mm -+++ b/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.mm -@@ -35,6 +35,7 @@ - #import "WebPageProxy.h" - #import "_WKUserContentWorldInternal.h" +diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushDaemonConnection.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushDaemonConnection.mm +index 8cd456770de0cd073370e97155b90eda3e7480a5..8e3975ae1fe673bd39facbfe787f143b80e24fb6 100644 +--- a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushDaemonConnection.mm ++++ b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushDaemonConnection.mm +@@ -32,6 +32,7 @@ + #import "WKSecurityOriginInternal.h" + #import "WebPushDaemonConnectionConfiguration.h" + #import "_WKNotificationDataInternal.h" ++#import "_WKWebPushMessageInternal.h" + #import "_WKWebPushSubscriptionDataInternal.h" + #import + #import +diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm +index 0a78daba00961bf10564a0b53067960b71d8b61d..696408b77c82e205a134edf2ee17ff971af226f3 100644 +--- a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm ++++ b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm +@@ -28,6 +28,9 @@ #import -+#import - #import + #import - @implementation _WKUserStyleSheet ++#import ++#import ++ + @implementation _WKWebPushSubscriptionData + + - (void)dealloc diff --git a/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..575245fc1f279a75f7e74c26652cf772a2fc95b7 @@ -10935,10 +10752,10 @@ index 0000000000000000000000000000000000000000..e0b1da48465c850f541532ed961d1b77 +WebKit::WebPageProxy* webkitBrowserInspectorCreateNewPageInContext(WebKitWebContext*); +void webkitBrowserInspectorQuitApplication(); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp -index bfc64d267c52ab6174bbde5c6f6471313ffbbd22..4110313841d5b4c8b944d52e24e76dac0710453d 100644 +index 9b6d8db85df969e609de036fac67374226ecd48e..2b293d5f24e562f06859432580f2cdfe40f8b9a6 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp -@@ -94,6 +94,10 @@ private: +@@ -101,6 +101,10 @@ private: page.makeViewBlankIfUnpaintedSinceLastLoadCommit(); webkitWebViewRunJavaScriptPrompt(m_webView, message.utf8(), defaultValue.utf8(), WTFMove(completionHandler)); } @@ -10950,10 +10767,10 @@ index bfc64d267c52ab6174bbde5c6f6471313ffbbd22..4110313841d5b4c8b944d52e24e76dac bool canRunBeforeUnloadConfirmPanel() const final { return true; } diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp -index f34220b0e7629d4bbdf311f73ce7a1b4d7212e0a..b4940b7058022c73402e5ea76b4e592a295f5b84 100644 +index b41b2938110b41a024b98215e2af31d960f1b936..502319020e384ee91b5367b10f48c71ff907560b 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp -@@ -421,10 +421,19 @@ static void webkitWebContextSetProperty(GObject* object, guint propID, const GVa +@@ -422,10 +422,19 @@ static void webkitWebContextSetProperty(GObject* object, guint propID, const GVa } } @@ -10973,7 +10790,7 @@ index f34220b0e7629d4bbdf311f73ce7a1b4d7212e0a..b4940b7058022c73402e5ea76b4e592a GUniquePtr bundleFilename(g_build_filename(injectedBundleDirectory(), INJECTED_BUNDLE_FILENAME, nullptr)); WebKitWebContext* webContext = WEBKIT_WEB_CONTEXT(object); -@@ -483,6 +492,8 @@ static void webkitWebContextConstructed(GObject* object) +@@ -484,6 +493,8 @@ static void webkitWebContextConstructed(GObject* object) static void webkitWebContextDispose(GObject* object) { @@ -10982,7 +10799,7 @@ index f34220b0e7629d4bbdf311f73ce7a1b4d7212e0a..b4940b7058022c73402e5ea76b4e592a WebKitWebContextPrivate* priv = WEBKIT_WEB_CONTEXT(object)->priv; if (!priv->clientsDetached) { priv->clientsDetached = true; -@@ -944,6 +955,11 @@ WebKitNetworkSession* webkit_web_context_get_network_session_for_automation(WebK +@@ -945,6 +956,11 @@ WebKitNetworkSession* webkit_web_context_get_network_session_for_automation(WebK return nullptr; #endif } @@ -10995,7 +10812,7 @@ index f34220b0e7629d4bbdf311f73ce7a1b4d7212e0a..b4940b7058022c73402e5ea76b4e592a /** * webkit_web_context_set_cache_model: diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in -index b8c2337af32ac3ce5be2b494f02c259392af994e..b1e4b2660fa30acad76888e2fe9bd50673a76549 100644 +index 15fe3e8e5652147ba54af266eda66b3962c074b9..d463fa78af375badb239c890da50ba1125e19de8 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in @@ -161,6 +161,10 @@ webkit_web_context_set_automation_allowed (WebKitWebContext @@ -11019,10 +10836,10 @@ index c1945fbe717a42afc1f51d64a80c7de3fa9009ba..ab63fe19b00ecbd64c9421e6eecad3e2 #endif +int webkitWebContextExistingCount(); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp -index 2d318375d33835ad78f75bd8169d9050ca850485..d607b8b2357c2b843b3654ccaa31fd7fe389b8a7 100644 +index 8f1821a8547e6f28032ba49a5f47344b916cd802..2dc19565002f98528b11b2d7a4fecd9ebb1a2b77 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp -@@ -34,6 +34,7 @@ +@@ -36,6 +36,7 @@ #include "WebContextMenuItem.h" #include "WebContextMenuItemData.h" #include "WebFrameProxy.h" @@ -11030,23 +10847,7 @@ index 2d318375d33835ad78f75bd8169d9050ca850485..d607b8b2357c2b843b3654ccaa31fd7f #include "WebKitAuthenticationRequestPrivate.h" #include "WebKitBackForwardListPrivate.h" #include "WebKitContextMenuClient.h" -@@ -51,6 +52,7 @@ - #include "WebKitNavigationClient.h" - #include "WebKitNotificationPrivate.h" - #include "WebKitPermissionStateQueryPrivate.h" -+#include "WebKitPointerLockPermissionRequest.h" - #include "WebKitPrivate.h" - #include "WebKitResponsePolicyDecision.h" - #include "WebKitScriptDialogPrivate.h" -@@ -91,7 +93,6 @@ - #if PLATFORM(GTK) - #include "WebKitFaviconDatabasePrivate.h" - #include "WebKitInputMethodContextImplGtk.h" --#include "WebKitPointerLockPermissionRequest.h" - #include "WebKitPrintOperationPrivate.h" - #include "WebKitWebInspectorPrivate.h" - #include "WebKitWebViewBasePrivate.h" -@@ -147,6 +148,7 @@ enum { +@@ -149,6 +150,7 @@ enum { CLOSE, SCRIPT_DIALOG, @@ -11054,7 +10855,7 @@ index 2d318375d33835ad78f75bd8169d9050ca850485..d607b8b2357c2b843b3654ccaa31fd7f DECIDE_POLICY, PERMISSION_REQUEST, -@@ -507,6 +509,16 @@ GRefPtr WebKitWebViewClient::showOptionMenu(WebKitPopupMenu& p +@@ -517,6 +519,16 @@ GRefPtr WebKitWebViewClient::showOptionMenu(WebKitPopupMenu& p void WebKitWebViewClient::frameDisplayed(WKWPE::View&) { @@ -11071,7 +10872,7 @@ index 2d318375d33835ad78f75bd8169d9050ca850485..d607b8b2357c2b843b3654ccaa31fd7f { SetForScope inFrameDisplayedGuard(m_webView->priv->inFrameDisplayed, true); for (const auto& callback : m_webView->priv->frameDisplayedCallbacks) { -@@ -523,6 +535,18 @@ void WebKitWebViewClient::frameDisplayed(WKWPE::View&) +@@ -533,6 +545,18 @@ void WebKitWebViewClient::frameDisplayed(WKWPE::View&) } } @@ -11090,7 +10891,7 @@ index 2d318375d33835ad78f75bd8169d9050ca850485..d607b8b2357c2b843b3654ccaa31fd7f void WebKitWebViewClient::willStartLoad(WKWPE::View&) { webkitWebViewWillStartLoad(m_webView); -@@ -609,7 +633,7 @@ static gboolean webkitWebViewDecidePolicy(WebKitWebView*, WebKitPolicyDecision* +@@ -619,7 +643,7 @@ static gboolean webkitWebViewDecidePolicy(WebKitWebView*, WebKitPolicyDecision* static gboolean webkitWebViewPermissionRequest(WebKitWebView*, WebKitPermissionRequest* request) { @@ -11099,7 +10900,7 @@ index 2d318375d33835ad78f75bd8169d9050ca850485..d607b8b2357c2b843b3654ccaa31fd7f if (WEBKIT_IS_POINTER_LOCK_PERMISSION_REQUEST(request)) { webkit_permission_request_allow(request); return TRUE; -@@ -929,6 +953,10 @@ static void webkitWebViewConstructed(GObject* object) +@@ -942,6 +966,10 @@ static void webkitWebViewConstructed(GObject* object) priv->websitePolicies = adoptGRef(webkit_website_policies_new()); Ref configuration = priv->relatedView && priv->relatedView->priv->configurationForNextRelatedView ? priv->relatedView->priv->configurationForNextRelatedView.releaseNonNull() : webkitWebViewCreatePageConfiguration(webView); @@ -11110,7 +10911,7 @@ index 2d318375d33835ad78f75bd8169d9050ca850485..d607b8b2357c2b843b3654ccaa31fd7f webkitWebViewCreatePage(webView, WTFMove(configuration)); webkitWebContextWebViewCreated(priv->context.get(), webView); -@@ -1958,6 +1986,15 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) +@@ -1981,6 +2009,15 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) G_TYPE_BOOLEAN, 1, WEBKIT_TYPE_SCRIPT_DIALOG); @@ -11126,7 +10927,7 @@ index 2d318375d33835ad78f75bd8169d9050ca850485..d607b8b2357c2b843b3654ccaa31fd7f /** * WebKitWebView::decide-policy: * @web_view: the #WebKitWebView on which the signal is emitted -@@ -2750,6 +2787,23 @@ void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView* webView, const +@@ -2766,6 +2803,23 @@ void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView* webView, const webkit_script_dialog_unref(webView->priv->currentScriptDialog); } @@ -11151,7 +10952,7 @@ index 2d318375d33835ad78f75bd8169d9050ca850485..d607b8b2357c2b843b3654ccaa31fd7f { if (!webView->priv->currentScriptDialog) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h -index 76f5b743cfe0a713897666545feb6fe07d6b16e8..4f13cca3cea9b20fbdb16cd5de0833832298d29a 100644 +index bf5b4c2bcca722e4d008f12194344c29c0db8824..ee6ee6b476ac28dee3a5983d03ba89ad0c9eb9ff 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h @@ -64,6 +64,7 @@ void webkitWebViewRunJavaScriptAlert(WebKitWebView*, const CString& message, Fun @@ -11163,7 +10964,7 @@ index 76f5b743cfe0a713897666545feb6fe07d6b16e8..4f13cca3cea9b20fbdb16cd5de083383 bool webkitWebViewIsScriptDialogRunning(WebKitWebView*, WebKitScriptDialog*); String webkitWebViewGetCurrentScriptDialogMessage(WebKitWebView*); diff --git a/Source/WebKit/UIProcess/API/glib/webkit.h.in b/Source/WebKit/UIProcess/API/glib/webkit.h.in -index 805f9f638c1630b5e9310494ae2970262de001cc..add3e80896c2e82bdd12cee15c8014bf88391ee0 100644 +index 763cd55f7abca011ac8bc4fef7f233bf52854cda..bd43917b274bf19ff9f3d96b7e80e20710372cba 100644 --- a/Source/WebKit/UIProcess/API/glib/webkit.h.in +++ b/Source/WebKit/UIProcess/API/glib/webkit.h.in @@ -45,6 +45,7 @@ @@ -11175,10 +10976,10 @@ index 805f9f638c1630b5e9310494ae2970262de001cc..add3e80896c2e82bdd12cee15c8014bf #include <@API_INCLUDE_PREFIX@/WebKitClipboardPermissionRequest.h> #include <@API_INCLUDE_PREFIX@/WebKitColorChooserRequest.h> diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp -index 8deb2ea57ad6e55b79053d392ef43e6191e036f4..54f45f129acb3b83aaae11f7895c749d20c3ce9e 100644 +index ebd7d55886465375c70fb3265f6655fe43c62966..b5d2169c2b76474f12038727a66cf69e5ed23ebd 100644 --- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp -@@ -273,6 +273,8 @@ void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool +@@ -268,6 +268,8 @@ void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool { if (wasEventHandled || event.type() != WebEventType::KeyDown || !event.nativeEvent()) return; @@ -11187,7 +10988,7 @@ index 8deb2ea57ad6e55b79053d392ef43e6191e036f4..54f45f129acb3b83aaae11f7895c749d // Always consider arrow keys as handled, otherwise the GtkWindow key bindings will move the focus. guint keyval; -@@ -371,9 +373,9 @@ void PageClientImpl::selectionDidChange() +@@ -366,9 +368,9 @@ void PageClientImpl::selectionDidChange() webkitWebViewSelectionDidChange(WEBKIT_WEB_VIEW(m_viewWidget)); } @@ -11200,7 +11001,7 @@ index 8deb2ea57ad6e55b79053d392ef43e6191e036f4..54f45f129acb3b83aaae11f7895c749d void PageClientImpl::didChangeContentSize(const IntSize& size) diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h -index 56693a6cace9e41e6f353393303e36290de768fe..f28839fee5f3769d0cebf2836615d0c91fddfb76 100644 +index 536e66027bdcfec08e28503d3dd715e3c51a2c9f..2cfba18152fd87c10e1bb7630515a677799f1bbc 100644 --- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h +++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h @@ -109,7 +109,7 @@ private: @@ -11313,10 +11114,10 @@ index 496079da90993ac37689b060b69ecd4a67c2b6a8..af30181ca922f16c0f6e245c70e5ce7d G_BEGIN_DECLS diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp -index 55efbd0732f7d74fc0702d012d13465686b9bfae..9efb28a02ddb82da4b7ae0868ec29e5ec95af6f1 100644 +index 1d118b75a4be169d624ac18b50b13096bf7e1f36..29e48279f82dfaf83016c97349b284d054e1b956 100644 --- a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp +++ b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp -@@ -2894,6 +2894,11 @@ void webkitWebViewBaseResetClickCounter(WebKitWebViewBase* webkitWebViewBase) +@@ -2884,6 +2884,11 @@ void webkitWebViewBaseResetClickCounter(WebKitWebViewBase* webkitWebViewBase) #endif } @@ -11328,7 +11129,7 @@ index 55efbd0732f7d74fc0702d012d13465686b9bfae..9efb28a02ddb82da4b7ae0868ec29e5e void webkitWebViewBaseEnterAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase, const LayerTreeContext& layerTreeContext) { ASSERT(webkitWebViewBase->priv->acceleratedBackingStore); -@@ -2950,12 +2955,12 @@ void webkitWebViewBasePageClosed(WebKitWebViewBase* webkitWebViewBase) +@@ -2940,12 +2945,12 @@ void webkitWebViewBasePageClosed(WebKitWebViewBase* webkitWebViewBase) webkitWebViewBase->priv->acceleratedBackingStore->update({ }); } @@ -11402,7 +11203,7 @@ index 7636ad733e7be66a74f8fede966b0acb905a5842..cf54287353d1e529c6765e3caf8d283a virtual void didChangePageID(WKWPE::View&) { } virtual void didReceiveUserMessage(WKWPE::View&, WebKit::UserMessage&&, CompletionHandler&& completionHandler) { completionHandler(WebKit::UserMessage()); } diff --git a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp -index ee491999df7919658c48d8eb457577335d3c5b90..09b834a89f84fb6b37f059c2cc4cce98313817e2 100644 +index 97b321f1d8bb33175f963af0f6ffe741b50e28e6..d03085cbaad14e3ed88817bf5f26facbe9a24538 100644 --- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp @@ -34,9 +34,13 @@ @@ -11432,16 +11233,7 @@ index ee491999df7919658c48d8eb457577335d3c5b90..09b834a89f84fb6b37f059c2cc4cce98 namespace WebKit { WTF_MAKE_TZONE_ALLOCATED_IMPL(PageClientImpl); -@@ -212,7 +222,7 @@ WebCore::IntPoint PageClientImpl::accessibilityScreenToRootView(const WebCore::I - - WebCore::IntRect PageClientImpl::rootViewToAccessibilityScreen(const WebCore::IntRect& rect) - { -- return rootViewToScreen(rect); -+ return rootViewToScreen(rect); - } - - void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent&, bool) -@@ -491,6 +501,64 @@ void PageClientImpl::selectionDidChange() +@@ -487,6 +497,64 @@ void PageClientImpl::selectionDidChange() m_view.selectionDidChange(); } @@ -11506,7 +11298,7 @@ index ee491999df7919658c48d8eb457577335d3c5b90..09b834a89f84fb6b37f059c2cc4cce98 WebKitWebResourceLoadManager* PageClientImpl::webResourceLoadManager() { return m_view.webResourceLoadManager(); -@@ -501,4 +569,23 @@ void PageClientImpl::callAfterNextPresentationUpdate(CompletionHandler&& +@@ -497,4 +565,23 @@ void PageClientImpl::callAfterNextPresentationUpdate(CompletionHandler&& m_view.callAfterNextPresentationUpdate(WTFMove(callback)); } @@ -11517,7 +11309,7 @@ index ee491999df7919658c48d8eb457577335d3c5b90..09b834a89f84fb6b37f059c2cc4cce98 +} +#endif + -+RefPtr PageClientImpl::createColorPicker(WebPageProxy* page, const WebCore::Color& color, const WebCore::IntRect& rect, Vector&&) ++RefPtr PageClientImpl::createColorPicker(WebPageProxy* page, const WebCore::Color& color, const WebCore::IntRect& rect, ColorControlSupportsAlpha, Vector&&) +{ + return WebColorPickerWPE::create(*page, color, rect); +} @@ -11531,10 +11323,10 @@ index ee491999df7919658c48d8eb457577335d3c5b90..09b834a89f84fb6b37f059c2cc4cce98 + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h -index 8397c722a45b279415f1648ad4673e99240089d9..41955881ad0db72ba0a27f4960330bb8dc237d2a 100644 +index 353515ae3a699d85314a924ba6fc4e9610ade23b..8a541023be8549e2c1fced51af6ed03dcd67fc6f 100644 --- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h +++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h -@@ -171,9 +171,24 @@ private: +@@ -170,9 +170,24 @@ private: void didChangeWebPageID() const override; void selectionDidChange() override; @@ -11551,7 +11343,7 @@ index 8397c722a45b279415f1648ad4673e99240089d9..41955881ad0db72ba0a27f4960330bb8 +#endif + +#if ENABLE(INPUT_TYPE_COLOR) -+ RefPtr createColorPicker(WebPageProxy*, const WebCore::Color& initialColor, const WebCore::IntRect&, Vector&&) override; ++ RefPtr createColorPicker(WebPageProxy*, const WebCore::Color& initialColor, const WebCore::IntRect&, ColorControlSupportsAlpha, Vector&&) override; +#endif +#if ENABLE(DATE_AND_TIME_INPUT_TYPES) + RefPtr createDateTimePicker(WebPageProxy&) override; @@ -11866,10 +11658,10 @@ index 2f1182cb91a00353eace0b71612df096391c2450..d71d7fc724b046fab41285bb8f390cb6 void didChangePageID(WKWPE::View&) override; void didReceiveUserMessage(WKWPE::View&, WebKit::UserMessage&&, CompletionHandler&&) override; diff --git a/Source/WebKit/UIProcess/Automation/WebAutomationSession.h b/Source/WebKit/UIProcess/Automation/WebAutomationSession.h -index 1f2e33b690d6be4f27838008f0eb32696023c8c7..4cf688212cd7c57fc46b376e6be7b7b51fe342de 100644 +index 62250eac7b9d4e38b3d9ccad743daaf1627ff017..218f379aea078cfa27c0af5a963a2d3dcbcbc66a 100644 --- a/Source/WebKit/UIProcess/Automation/WebAutomationSession.h +++ b/Source/WebKit/UIProcess/Automation/WebAutomationSession.h -@@ -236,6 +236,8 @@ public: +@@ -270,6 +270,8 @@ public: void didDestroyFrame(WebCore::FrameIdentifier); @@ -11878,7 +11670,7 @@ index 1f2e33b690d6be4f27838008f0eb32696023c8c7..4cf688212cd7c57fc46b376e6be7b7b5 private: RefPtr webPageProxyForHandle(const String&); String handleForWebPageProxy(const WebPageProxy&); -@@ -287,7 +289,6 @@ private: +@@ -320,7 +322,6 @@ private: // Get base64-encoded PNG data from a bitmap. static std::optional platformGetBase64EncodedPNGData(WebCore::ShareableBitmap::Handle&&); @@ -11887,10 +11679,10 @@ index 1f2e33b690d6be4f27838008f0eb32696023c8c7..4cf688212cd7c57fc46b376e6be7b7b5 // Save base64-encoded file contents to a local file path and return the path. // This reuses the basename of the remote file path so that the filename exposed to DOM API remains the same. diff --git a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp -index a3a4997f987ba09829d54f26c1cc70842c658f87..b8cb97db12695db3bec61a01cf8073213b40f6ac 100644 +index 9d98e6bf5266ed4cafd77f646be8bdaeefc33cd3..c9a3288d9c0f6d3c735f6d79b70eb852f95602e8 100644 --- a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp +++ b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp -@@ -168,7 +168,11 @@ void AuxiliaryProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& lau +@@ -169,7 +169,11 @@ void AuxiliaryProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& lau launchOptions.processCmdPrefix = String::fromUTF8(processCmdPrefix); #endif // ENABLE(DEVELOPER_MODE) && (PLATFORM(GTK) || PLATFORM(WPE)) @@ -11903,10 +11695,10 @@ index a3a4997f987ba09829d54f26c1cc70842c658f87..b8cb97db12695db3bec61a01cf807321 platformGetLaunchOptions(launchOptions); } diff --git a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h -index 70aa53ec6d79c71bf2394e88f7e4c3bc8f70d4ec..bea35c50cc2288f16f86c4930d565e1247a1bba9 100644 +index a8ee41c1155989a57a5c0bd09c5144e8103c7c7c..172d567478e36d275a23ae3db82281f4a7af5c26 100644 --- a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h +++ b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h -@@ -294,13 +294,16 @@ protected: +@@ -296,13 +296,16 @@ protected: InitializationActivityAndGrant initializationActivityAndGrant(); @@ -11925,10 +11717,10 @@ index 70aa53ec6d79c71bf2394e88f7e4c3bc8f70d4ec..bea35c50cc2288f16f86c4930d565e12 // Connection::Client diff --git a/Source/WebKit/UIProcess/BackingStore.h b/Source/WebKit/UIProcess/BackingStore.h -index 945c62704e0b25f04e9ee4be88b21f88aeda8bd9..409c1c560b2462bf59f19dfee7941748b54fd22c 100644 +index f72e17dc0973d4523c4b29a14754ec6d6036e06f..153f7b8495404513e20db757c0269f9e3c4d0e2d 100644 --- a/Source/WebKit/UIProcess/BackingStore.h +++ b/Source/WebKit/UIProcess/BackingStore.h -@@ -67,6 +67,7 @@ public: +@@ -69,6 +69,7 @@ public: float deviceScaleFactor() const { return m_deviceScaleFactor; } void paint(PlatformPaintContextPtr, const WebCore::IntRect&); @@ -12047,44 +11839,23 @@ index 0000000000000000000000000000000000000000..cd66887de171cda7d15a8e4dc6dbff63 +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) -diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h -index aaa27547f4ad4e3cc5551f621472554f4ed287bb..294e11d5b5cac544b62254e9951580b4339f0f17 100644 ---- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h -+++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h -@@ -29,6 +29,7 @@ +diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h +index 1eb07a8bfadb2c4477698940b9429eefacc7d059..30e8b82bb1d8ca88ec5af80580c0ca751d10485f 100644 +--- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h ++++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h +@@ -25,6 +25,7 @@ - #include "SOAuthorizationSession.h" - #include -+#include + #if HAVE(APP_SSO) - OBJC_CLASS WKSOSecretDelegate; - OBJC_CLASS WKWebView; -@@ -40,6 +41,8 @@ class PageConfiguration; ++#import "SOAuthorizationSession.h" + #import namespace WebKit { - -+class WebPageProxy; -+ - // FSM: Idle => Active => Completed - class PopUpSOAuthorizationSession final : public SOAuthorizationSession { - public: -diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/SOAuthorizationCoordinator.h b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/SOAuthorizationCoordinator.h -index 11caa19f1f40a55fa4378ac092632731cd16f9e0..56b6ec4a8a1f6dfd199e24a91bb4c9113ba6e08c 100644 ---- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/SOAuthorizationCoordinator.h -+++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/SOAuthorizationCoordinator.h -@@ -27,6 +27,7 @@ - - #if HAVE(APP_SSO) - -+#import "APIPageConfiguration.h" - #include - #include - #include diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h -index 49c6fb1049761c89e9e0e40869f4d57d042c227b..acaa86f77435ba1be932e574d4b62ae2716f27e8 100644 +index 47da0ee168267f6a4a27602ea0c3cffdeb0a8a44..70eef746a34ebc037e56b4a81675e1184a37d178 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h -@@ -106,6 +106,7 @@ private: +@@ -102,6 +102,7 @@ private: void runJavaScriptAlert(WebPageProxy&, const WTF::String&, WebFrameProxy*, FrameInfoData&&, Function&& completionHandler) final; void runJavaScriptConfirm(WebPageProxy&, const WTF::String&, WebFrameProxy*, FrameInfoData&&, Function&& completionHandler) final; void runJavaScriptPrompt(WebPageProxy&, const WTF::String&, const WTF::String&, WebFrameProxy*, FrameInfoData&&, Function&&) final; @@ -12092,7 +11863,7 @@ index 49c6fb1049761c89e9e0e40869f4d57d042c227b..acaa86f77435ba1be932e574d4b62ae2 void presentStorageAccessConfirmDialog(const WTF::String& requestingDomain, const WTF::String& currentDomain, CompletionHandler&&); void requestStorageAccessConfirm(WebPageProxy&, WebFrameProxy*, const WebCore::RegistrableDomain& requestingDomain, const WebCore::RegistrableDomain& currentDomain, std::optional&&, CompletionHandler&&) final; void decidePolicyForGeolocationPermissionRequest(WebPageProxy&, WebFrameProxy&, const FrameInfoData&, Function&) final; -@@ -223,6 +224,7 @@ private: +@@ -220,6 +221,7 @@ private: bool webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler : 1; bool webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1; bool webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler : 1; @@ -12101,10 +11872,10 @@ index 49c6fb1049761c89e9e0e40869f4d57d042c227b..acaa86f77435ba1be932e574d4b62ae2 bool webViewRequestStorageAccessPanelForDomainUnderCurrentDomainForQuirkDomainsCompletionHandler : 1; bool webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1; diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm -index 45d81b21bbc47418f77dd5a49c032c694db3f08c..10466388e3380e939ad8199f059b25491a61e48f 100644 +index de8a55897d3fd5bcb31d15b4eec187ebeaac21e6..fb5855993c24d2d5c766660435bd545dd39a59b0 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm -@@ -122,6 +122,7 @@ void UIDelegate::setDelegate(id delegate) +@@ -134,6 +134,7 @@ void UIDelegate::setDelegate(id delegate) m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)]; m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)]; m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)]; @@ -12112,7 +11883,7 @@ index 45d81b21bbc47418f77dd5a49c032c694db3f08c..10466388e3380e939ad8199f059b2549 m_delegateMethods.webViewRequestStorageAccessPanelUnderFirstPartyCompletionHandler = [delegate respondsToSelector:@selector(_webView:requestStorageAccessPanelForDomain:underCurrentDomain:completionHandler:)]; m_delegateMethods.webViewRequestStorageAccessPanelForDomainUnderCurrentDomainForQuirkDomainsCompletionHandler = [delegate respondsToSelector:@selector(_webView:requestStorageAccessPanelForDomain:underCurrentDomain:forQuirkDomains:completionHandler:)]; m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:)]; -@@ -458,6 +459,15 @@ void UIDelegate::UIClient::runJavaScriptPrompt(WebPageProxy& page, const WTF::St +@@ -465,6 +466,15 @@ void UIDelegate::UIClient::runJavaScriptPrompt(WebPageProxy& page, const WTF::St }).get()]; } @@ -12127,9 +11898,9 @@ index 45d81b21bbc47418f77dd5a49c032c694db3f08c..10466388e3380e939ad8199f059b2549 + void UIDelegate::UIClient::requestStorageAccessConfirm(WebPageProxy& webPageProxy, WebFrameProxy*, const WebCore::RegistrableDomain& requestingDomain, const WebCore::RegistrableDomain& currentDomain, std::optional&& organizationStorageAccessPromptQuirk, CompletionHandler&& completionHandler) { - if (!m_uiDelegate) + RefPtr uiDelegate = m_uiDelegate.get(); diff --git a/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm b/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm -index 2d04117422e1e10ca59fec5af93b312352b948e5..d7a04374498d58311914ca538d316f362164ac62 100644 +index 064f96db74bdf0df821846540d18e4792f3b2963..e4a0316168f739ef5b667006ceaf00ff30341e6c 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm @@ -42,7 +42,9 @@ @@ -12142,7 +11913,7 @@ index 2d04117422e1e10ca59fec5af93b312352b948e5..d7a04374498d58311914ca538d316f36 #import "PlatformXRSystem.h" #import "PlaybackSessionManagerProxy.h" #import "QuickLookThumbnailLoader.h" -@@ -317,11 +319,86 @@ bool WebPageProxy::scrollingUpdatesDisabledForTesting() +@@ -322,11 +324,86 @@ bool WebPageProxy::scrollingUpdatesDisabledForTesting() void WebPageProxy::startDrag(const DragItem& dragItem, ShareableBitmap::Handle&& dragImageHandle) { @@ -12231,10 +12002,10 @@ index 2d04117422e1e10ca59fec5af93b312352b948e5..d7a04374498d58311914ca538d316f36 #if ENABLE(ATTACHMENT_ELEMENT) diff --git a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm -index 2d583997574502b60b74208ad01349b7f1bc17d2..ffa9871e3679684d82d508c91137651231112c20 100644 +index c16012314db5eee29263ea19d7627eaf3d9cfe79..7544eecb359d3263e2d3222658687fcfebb07af6 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm -@@ -436,7 +436,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END +@@ -437,7 +437,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END auto screenProperties = WebCore::collectScreenProperties(); parameters.screenProperties = WTFMove(screenProperties); #if PLATFORM(MAC) @@ -12243,7 +12014,7 @@ index 2d583997574502b60b74208ad01349b7f1bc17d2..ffa9871e3679684d82d508c911376512 #endif #if (PLATFORM(IOS) || PLATFORM(VISION)) && HAVE(AGX_COMPILER_SERVICE) -@@ -831,8 +831,8 @@ void WebProcessPool::registerNotificationObservers() +@@ -832,8 +832,8 @@ void WebProcessPool::registerNotificationObservers() }]; m_scrollerStyleNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSPreferredScrollerStyleDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) { @@ -12255,7 +12026,7 @@ index 2d583997574502b60b74208ad01349b7f1bc17d2..ffa9871e3679684d82d508c911376512 m_activationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidBecomeActiveNotification object:NSApp queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) { diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp -index d15636e78679112ea910a43d45b2930676b15d6a..72c9a4c6327712073190c33774bec559bf026003 100644 +index 9aeeff96ce40d58fe51124275b8fb60e8609d254..4840c7bb5c1ca1380205fd0167870b81bf3d873d 100644 --- a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp +++ b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp @@ -33,6 +33,7 @@ @@ -12291,7 +12062,7 @@ index d15636e78679112ea910a43d45b2930676b15d6a..72c9a4c6327712073190c33774bec559 namespace WebKit { using namespace WebCore; -@@ -164,6 +174,11 @@ void DrawingAreaProxyCoordinatedGraphics::deviceScaleFactorDidChange(CompletionH +@@ -180,6 +190,11 @@ void DrawingAreaProxyCoordinatedGraphics::deviceScaleFactorDidChange(CompletionH completionHandler(); } @@ -12303,7 +12074,7 @@ index d15636e78679112ea910a43d45b2930676b15d6a..72c9a4c6327712073190c33774bec559 void DrawingAreaProxyCoordinatedGraphics::setBackingStoreIsDiscardable(bool isBackingStoreDiscardable) { #if !PLATFORM(WPE) -@@ -225,6 +240,45 @@ void DrawingAreaProxyCoordinatedGraphics::updateAcceleratedCompositingMode(uint6 +@@ -241,6 +256,45 @@ void DrawingAreaProxyCoordinatedGraphics::updateAcceleratedCompositingMode(uint6 updateAcceleratedCompositingMode(layerTreeContext); } @@ -12348,8 +12119,8 @@ index d15636e78679112ea910a43d45b2930676b15d6a..72c9a4c6327712073190c33774bec559 + bool DrawingAreaProxyCoordinatedGraphics::alwaysUseCompositing() const { - return m_webPageProxy->preferences().acceleratedCompositingEnabled() && m_webPageProxy->preferences().forceCompositingMode(); -@@ -279,6 +333,12 @@ void DrawingAreaProxyCoordinatedGraphics::didUpdateGeometry() + if (!m_webPageProxy) +@@ -308,6 +362,12 @@ void DrawingAreaProxyCoordinatedGraphics::didUpdateGeometry() // we need to resend the new size here. if (m_lastSentSize != m_size) sendUpdateGeometry(); @@ -12363,7 +12134,7 @@ index d15636e78679112ea910a43d45b2930676b15d6a..72c9a4c6327712073190c33774bec559 #if !PLATFORM(WPE) diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h -index a7cf6a9f232b4c2d6803ed8d6b3fa2273bfe0a2e..5fbbe2a55625f651e190b0c2197b9c7f97814624 100644 +index 9c2bde0db0e4032a32e6ae02dc45af335df92f7a..7ae72e6c791c264ea7e0db4c93a0422b5b699e19 100644 --- a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h +++ b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h @@ -29,6 +29,7 @@ @@ -12371,10 +12142,10 @@ index a7cf6a9f232b4c2d6803ed8d6b3fa2273bfe0a2e..5fbbe2a55625f651e190b0c2197b9c7f #include "DrawingAreaProxy.h" #include "LayerTreeContext.h" +#include + #include #include #include - -@@ -56,6 +57,10 @@ public: +@@ -60,6 +61,10 @@ public: bool isInAcceleratedCompositingMode() const { return !m_layerTreeContext.isEmpty(); } const LayerTreeContext& layerTreeContext() const { return m_layerTreeContext; } @@ -12385,17 +12156,17 @@ index a7cf6a9f232b4c2d6803ed8d6b3fa2273bfe0a2e..5fbbe2a55625f651e190b0c2197b9c7f void dispatchAfterEnsuringDrawing(CompletionHandler&&); -@@ -79,6 +84,9 @@ private: - void enterAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext&) override; +@@ -86,6 +91,9 @@ private: void exitAcceleratedCompositingMode(uint64_t backingStoreStateID, UpdateInfo&&) override; void updateAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext&) override; + void dispatchPresentationCallbacksAfterFlushingLayers(IPC::Connection&, Vector&&) override; +#if PLATFORM(WIN) + void didChangeAcceleratedCompositingMode(bool enabled) override; +#endif bool shouldSendWheelEventsToEventDispatcher() const override { return true; } -@@ -122,6 +130,7 @@ private: +@@ -129,6 +137,7 @@ private: // The last size we sent to the web process. WebCore::IntSize m_lastSentSize; @@ -12403,7 +12174,7 @@ index a7cf6a9f232b4c2d6803ed8d6b3fa2273bfe0a2e..5fbbe2a55625f651e190b0c2197b9c7f #if !PLATFORM(WPE) bool m_isBackingStoreDiscardable { true }; -@@ -130,6 +139,10 @@ private: +@@ -137,6 +146,10 @@ private: RunLoop::Timer m_discardBackingStoreTimer; #endif std::unique_ptr m_drawingMonitor; @@ -12415,10 +12186,10 @@ index a7cf6a9f232b4c2d6803ed8d6b3fa2273bfe0a2e..5fbbe2a55625f651e190b0c2197b9c7f } // namespace WebKit diff --git a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp b/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp -index 81b64958bf7f9e86a54bc41028aea1b983ce7133..bd9697fc26ca4c903891178bfd884ee35c953eed 100644 +index 8fe224d8c374d0a7cabb1cbf02b678061e58bacf..89be23d0d8759097c0d6b2c9bf9df614ddc278a5 100644 --- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp +++ b/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp -@@ -40,8 +40,10 @@ +@@ -41,8 +41,10 @@ #include #include #include @@ -12429,10 +12200,10 @@ index 81b64958bf7f9e86a54bc41028aea1b983ce7133..bd9697fc26ca4c903891178bfd884ee3 #if PLATFORM(MAC) #include -@@ -62,7 +64,10 @@ DownloadProxy::DownloadProxy(DownloadProxyMap& downloadProxyMap, WebsiteDataStor - , m_request(resourceRequest) - , m_originatingPage(originatingPage) - , m_frameInfo(API::FrameInfo::create(FrameInfoData { frameInfoData }, originatingPage)) +@@ -66,7 +68,10 @@ DownloadProxy::DownloadProxy(DownloadProxyMap& downloadProxyMap, WebsiteDataStor + #if HAVE(MODERN_DOWNLOADPROGRESS) + , m_assertion(ProcessAssertion::create(getCurrentProcessID(), "WebKit DownloadProxy DecideDestination"_s, ProcessAssertionType::FinishTaskInterruptable)) + #endif + , m_uuid(createVersion4UUIDString()) { + if (auto* instrumentation = m_dataStore->downloadInstrumentation()) @@ -12440,21 +12211,24 @@ index 81b64958bf7f9e86a54bc41028aea1b983ce7133..bd9697fc26ca4c903891178bfd884ee3 } DownloadProxy::~DownloadProxy() -@@ -81,9 +86,12 @@ static RefPtr createData(std::span data) - void DownloadProxy::cancel(CompletionHandler&& completionHandler) +@@ -86,12 +91,15 @@ void DownloadProxy::cancel(CompletionHandler&& completionHandl { + m_downloadIsCancelled = true; if (m_dataStore) { -- protectedDataStore()->protectedNetworkProcess()->sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler)] (std::span resumeData) mutable { +- protectedDataStore()->protectedNetworkProcess()->sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [weakThis = WeakPtr { *this }, completionHandler = WTFMove(completionHandler)] (std::span resumeData) mutable { + auto* instrumentation = m_dataStore->downloadInstrumentation(); -+ protectedDataStore()->protectedNetworkProcess()->sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler), instrumentation] (std::span resumeData) mutable { - m_legacyResumeData = createData(resumeData); - completionHandler(m_legacyResumeData.get()); ++ protectedDataStore()->protectedNetworkProcess()->sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [weakThis = WeakPtr { *this }, completionHandler = WTFMove(completionHandler), instrumentation] (std::span resumeData) mutable { + RefPtr protectedThis = weakThis.get(); + if (!protectedThis) + return completionHandler(nullptr); + protectedThis->m_legacyResumeData = createData(resumeData); + completionHandler(protectedThis->m_legacyResumeData.get()); + if (instrumentation) -+ instrumentation->downloadFinished(m_uuid, "canceled"_s); - m_downloadProxyMap->downloadFinished(*this); ++ instrumentation->downloadFinished(protectedThis->m_uuid, "canceled"_s); + if (RefPtr downloadProxyMap = protectedThis->m_downloadProxyMap.get()) + downloadProxyMap->downloadFinished(*protectedThis); }); - } else -@@ -153,6 +161,33 @@ void DownloadProxy::decideDestinationWithSuggestedFilename(const WebCore::Resour +@@ -163,6 +171,33 @@ void DownloadProxy::decideDestinationWithSuggestedFilename(const WebCore::Resour suggestedFilename = m_suggestedFilename; suggestedFilename = MIMETypeRegistry::appendFileExtensionIfNecessary(suggestedFilename, response.mimeType()); @@ -12485,19 +12259,19 @@ index 81b64958bf7f9e86a54bc41028aea1b983ce7133..bd9697fc26ca4c903891178bfd884ee3 + return; + } + - m_client->decideDestinationWithSuggestedFilename(*this, response, ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename), [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler)] (AllowOverwrite allowOverwrite, String destination) mutable { + protectedClient()->decideDestinationWithSuggestedFilename(*this, response, ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename), [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler)] (AllowOverwrite allowOverwrite, String destination) mutable { SandboxExtension::Handle sandboxExtensionHandle; if (!destination.isNull()) { -@@ -215,6 +250,8 @@ void DownloadProxy::didFinish() - updateQuarantinePropertiesIfPossible(); - #endif +@@ -227,6 +262,8 @@ void DownloadProxy::didFinish() m_client->didFinish(*this); + if (m_downloadIsCancelled) + return; + if (auto* instrumentation = m_dataStore->downloadInstrumentation()) + instrumentation->downloadFinished(m_uuid, String()); // This can cause the DownloadProxy object to be deleted. - m_downloadProxyMap->downloadFinished(*this); -@@ -225,6 +262,8 @@ void DownloadProxy::didFail(const ResourceError& error, std::span + if (RefPtr downloadProxyMap = m_downloadProxyMap.get()) +@@ -241,6 +278,8 @@ void DownloadProxy::didFail(const ResourceError& error, std::span m_legacyResumeData = createData(resumeData); m_client->didFail(*this, error, m_legacyResumeData.get()); @@ -12505,24 +12279,24 @@ index 81b64958bf7f9e86a54bc41028aea1b983ce7133..bd9697fc26ca4c903891178bfd884ee3 + instrumentation->downloadFinished(m_uuid, error.localizedDescription()); // This can cause the DownloadProxy object to be deleted. - m_downloadProxyMap->downloadFinished(*this); + if (RefPtr downloadProxyMap = m_downloadProxyMap.get()) diff --git a/Source/WebKit/UIProcess/Downloads/DownloadProxy.h b/Source/WebKit/UIProcess/Downloads/DownloadProxy.h -index 8418c16c5ee94c3ea37962d1db4b961d18dc391e..fb8a8ba64c499d92f17891e0268fe3c1163913c0 100644 +index 5c48a4c5f1747687ef5dace933feae900b02991e..1e85682f2f4351d2c2da955dd36abf95303320a6 100644 --- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.h +++ b/Source/WebKit/UIProcess/Downloads/DownloadProxy.h -@@ -156,6 +156,7 @@ private: - #if PLATFORM(COCOA) - RetainPtr m_progress; +@@ -166,6 +166,7 @@ private: + #if HAVE(MODERN_DOWNLOADPROGRESS) + RefPtr m_assertion; #endif + String m_uuid; }; } // namespace WebKit diff --git a/Source/WebKit/UIProcess/DrawingAreaProxy.h b/Source/WebKit/UIProcess/DrawingAreaProxy.h -index a6897e8688b39c7ca3131b3b730a0fec1d3727e2..0f0e67c3eaa49351266d7666189e168a4f9cce7c 100644 +index e1f55b4a7fbc452ca1f2eb025b0c88ec9f4b845f..4e4238f4f656208c0f11822406172ea13a21e2d4 100644 --- a/Source/WebKit/UIProcess/DrawingAreaProxy.h +++ b/Source/WebKit/UIProcess/DrawingAreaProxy.h -@@ -90,6 +90,7 @@ public: +@@ -94,6 +94,7 @@ public: const WebCore::IntSize& size() const { return m_size; } bool setSize(const WebCore::IntSize&, const WebCore::IntSize& scrollOffset = { }); @@ -12530,7 +12304,7 @@ index a6897e8688b39c7ca3131b3b730a0fec1d3727e2..0f0e67c3eaa49351266d7666189e168a virtual void minimumSizeForAutoLayoutDidChange() { } virtual void sizeToContentAutoSizeMaximumSizeDidChange() { } -@@ -177,6 +178,10 @@ private: +@@ -181,6 +182,10 @@ private: virtual void update(uint64_t /* backingStoreStateID */, UpdateInfo&&) { } virtual void exitAcceleratedCompositingMode(uint64_t /* backingStoreStateID */, UpdateInfo&&) { } #endif @@ -12542,10 +12316,10 @@ index a6897e8688b39c7ca3131b3b730a0fec1d3727e2..0f0e67c3eaa49351266d7666189e168a } // namespace WebKit diff --git a/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in b/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in -index fc5c53f18ad2dee2c2f40cdbb86ca7f24b262d8d..d93d804d3a8ebaa30856710df544f3db5aa7ad2d 100644 +index b03ac2dcf12c771da4a2347b81e5ba93fbd5f6a4..b69c5d3244306e1d1c10206d499d9a833a3efeec 100644 --- a/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in +++ b/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in -@@ -30,4 +30,7 @@ messages -> DrawingAreaProxy NotRefCounted { +@@ -35,4 +35,7 @@ messages -> DrawingAreaProxy { Update(uint64_t stateID, struct WebKit::UpdateInfo updateInfo) CanDispatchOutOfOrder ExitAcceleratedCompositingMode(uint64_t backingStoreStateID, struct WebKit::UpdateInfo updateInfo) #endif @@ -12843,10 +12617,10 @@ index 0000000000000000000000000000000000000000..4ec8b96bbbddf8a7b042f53a8068754a +cairo_status_t cairo_image_surface_write_to_jpeg_mem(cairo_surface_t *sfc, unsigned char **data, size_t *len, int quality); diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..229fd8e721648b07057af413f0fb8424af2ed926 +index 0000000000000000000000000000000000000000..033bf77bca2de127e55cbf55a9e0b0c358fc81f9 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp -@@ -0,0 +1,387 @@ +@@ -0,0 +1,392 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * @@ -12883,6 +12657,7 @@ index 0000000000000000000000000000000000000000..229fd8e721648b07057af413f0fb8424 +#include +#include +#include ++#include +#include +#include +#include @@ -12909,6 +12684,8 @@ index 0000000000000000000000000000000000000000..229fd8e721648b07057af413f0fb8424 +#include +#endif + ++WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN ++ +namespace WebKit { + +const int kMaxFramesInFlight = 1; @@ -13234,6 +13011,8 @@ index 0000000000000000000000000000000000000000..229fd8e721648b07057af413f0fb8424 +#endif + +} // namespace WebKit ++ ++WTF_ALLOW_UNSAFE_BUFFER_USAGE_END diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..f53bb59c65a4ced0360e473fb9ed9a36d1179310 @@ -13351,10 +13130,10 @@ index 0000000000000000000000000000000000000000..f53bb59c65a4ced0360e473fb9ed9a36 +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..9f3a9fb9ca1881b9c81493bf5a21382d4015c74c +index 0000000000000000000000000000000000000000..760f6ab8714c45f0019e583970767ea40e35d818 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp -@@ -0,0 +1,438 @@ +@@ -0,0 +1,443 @@ +/* + * Copyright (c) 2010, The WebM Project authors. All rights reserved. + * Copyright (c) 2013 The Chromium Authors. All rights reserved. @@ -13391,6 +13170,7 @@ index 0000000000000000000000000000000000000000..9f3a9fb9ca1881b9c81493bf5a21382d +#include +#include +#include ++#include +#include +#include +#include @@ -13408,6 +13188,8 @@ index 0000000000000000000000000000000000000000..9f3a9fb9ca1881b9c81493bf5a21382d +#include +#endif + ++WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN ++ +using namespace WebCore; + +namespace WebKit { @@ -13793,6 +13575,8 @@ index 0000000000000000000000000000000000000000..9f3a9fb9ca1881b9c81493bf5a21382d + + +} // namespace WebKit ++ ++WTF_ALLOW_UNSAFE_BUFFER_USAGE_END diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h new file mode 100644 index 0000000000000000000000000000000000000000..caf0474267c1bda6346f7b025b6646bb4f1b56d9 @@ -14016,7 +13800,7 @@ index 0000000000000000000000000000000000000000..e2ce910f3fd7f587add552275b7e7176 + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp -index 23426ee5d9f3a01e5216267810f48091779384ca..78edcf784aa90cd9296faa539d235e741f826d32 100644 +index 77bdb25abf77bc0f7f00d3dbd57b0eb751c99488..6d3a93a009cff0f70f2b1a1e674827c24a26a947 100644 --- a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp +++ b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp @@ -28,7 +28,7 @@ @@ -14028,32 +13812,23 @@ index 23426ee5d9f3a01e5216267810f48091779384ca..78edcf784aa90cd9296faa539d235e74 #include "WebPageInspectorTarget.h" #include "WebPageMessages.h" #include "WebPageProxy.h" -@@ -43,19 +43,17 @@ WTF_MAKE_TZONE_ALLOCATED_IMPL(InspectorTargetProxy); - - std::unique_ptr InspectorTargetProxy::create(WebPageProxy& page, const String& targetId, Inspector::InspectorTargetType type) - { -- return makeUnique(page, targetId, type); -+ return makeUnique(page, nullptr, targetId, type); +@@ -46,13 +46,13 @@ std::unique_ptr InspectorTargetProxy::create(WebPageProxy& + return makeUnique(page, targetId, type); } -std::unique_ptr InspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId, Inspector::InspectorTargetType type) +std::unique_ptr InspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId) { -- Ref page = provisionalPage.page(); -- auto target = InspectorTargetProxy::create(page, targetId, type); -- target->m_provisionalPage = provisionalPage; -- return target; -+ return makeUnique(provisionalPage.page(), &provisionalPage, targetId, Inspector::InspectorTargetType::Page); - } - --InspectorTargetProxy::InspectorTargetProxy(WebPageProxy& page, const String& targetId, Inspector::InspectorTargetType type) -+InspectorTargetProxy::InspectorTargetProxy(WebPageProxy& page, ProvisionalPageProxy* provisionalPage, const String& targetId, Inspector::InspectorTargetType type) - : m_page(page) -+ , m_provisionalPage(provisionalPage) - , m_identifier(targetId) - , m_type(type) - { -@@ -102,6 +100,31 @@ void InspectorTargetProxy::didCommitProvisionalTarget() + RefPtr page = provisionalPage.page(); + if (!page) + return nullptr; + +- auto target = InspectorTargetProxy::create(*page, targetId, type); ++ auto target = InspectorTargetProxy::create(*page, targetId, Inspector::InspectorTargetType::Page); + target->m_provisionalPage = provisionalPage; + return target; + } +@@ -105,6 +105,31 @@ void InspectorTargetProxy::didCommitProvisionalTarget() m_provisionalPage = nullptr; } @@ -14086,10 +13861,10 @@ index 23426ee5d9f3a01e5216267810f48091779384ca..78edcf784aa90cd9296faa539d235e74 { return !!m_provisionalPage; diff --git a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h -index edd6e7f1799279ed3d0eb81b6c2eef9f5b375134..4552047ddc305d1da8ab2c0ca319392d95359a2c 100644 +index edd6e7f1799279ed3d0eb81b6c2eef9f5b375134..d4231f84f3c52641f4d9e88559e8e1a4845b7163 100644 --- a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h +++ b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h -@@ -38,13 +38,13 @@ class WebPageProxy; +@@ -38,12 +38,12 @@ class WebPageProxy; // NOTE: This UIProcess side InspectorTarget doesn't care about the frontend channel, since // any target -> frontend messages will be routed to the WebPageProxy with a targetId. @@ -14100,13 +13875,11 @@ index edd6e7f1799279ed3d0eb81b6c2eef9f5b375134..4552047ddc305d1da8ab2c0ca319392d public: static std::unique_ptr create(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); - static std::unique_ptr create(ProvisionalPageProxy&, const String& targetId, Inspector::InspectorTargetType); -- InspectorTargetProxy(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); + static std::unique_ptr create(ProvisionalPageProxy&, const String& targetId); -+ InspectorTargetProxy(WebPageProxy&, ProvisionalPageProxy*, const String& targetId, Inspector::InspectorTargetType); + InspectorTargetProxy(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); ~InspectorTargetProxy() = default; - Inspector::InspectorTargetType type() const final { return m_type; } -@@ -56,12 +56,17 @@ public: +@@ -56,8 +56,13 @@ public: void connect(Inspector::FrontendChannel::ConnectionType) override; void disconnect() override; void sendMessageToTargetBackend(const String&) override; @@ -14118,15 +13891,10 @@ index edd6e7f1799279ed3d0eb81b6c2eef9f5b375134..4552047ddc305d1da8ab2c0ca319392d + void platformActivate(String& error) const; + WeakRef m_page; -+ WeakPtr m_provisionalPage; String m_identifier; Inspector::InspectorTargetType m_type; -- WeakPtr m_provisionalPage; - }; - - } // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp -index e4f2f719746ed69b1226be2d47b16666f2067772..e94eba914cf44bad58c63be024a862d904baf690 100644 +index e4f2f719746ed69b1226be2d47b16666f2067772..c0e4452b9c8e286e1944b47e46acf49bdaee439a 100644 --- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp +++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp @@ -26,13 +26,21 @@ @@ -14393,7 +14161,7 @@ index e4f2f719746ed69b1226be2d47b16666f2067772..e94eba914cf44bad58c63be024a862d9 void WebPageInspectorController::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type) { addTarget(InspectorTargetProxy::create(protectedInspectedPage(), targetId, type)); -@@ -184,6 +363,32 @@ void WebPageInspectorController::sendMessageToInspectorFrontend(const String& ta +@@ -184,6 +363,48 @@ void WebPageInspectorController::sendMessageToInspectorFrontend(const String& ta m_targetAgent->sendMessageFromTargetToFrontend(targetId, message); } @@ -14403,7 +14171,7 @@ index e4f2f719746ed69b1226be2d47b16666f2067772..e94eba914cf44bad58c63be024a862d9 + m_targetAgent->setPauseOnStart(shouldPause); +} + -+bool WebPageInspectorController::shouldPauseLoading() const ++bool WebPageInspectorController::shouldPauseLoadRequest() const +{ + if (!m_frontendRouter->hasFrontends()) + return false; @@ -14412,10 +14180,26 @@ index e4f2f719746ed69b1226be2d47b16666f2067772..e94eba914cf44bad58c63be024a862d9 + return false; + + auto* target = m_targets.get(WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess())); ++ // The method is expeted to be called only when the WebPage has already been ++ // initilized, so the target must exist. + ASSERT(target); + return target->isPaused(); +} + ++bool WebPageInspectorController::shouldPauseInInspectorWhenShown() const ++{ ++ if (!m_frontendRouter->hasFrontends()) ++ return false; ++ ++ if (!m_inspectedPage->isPageOpenedByDOMShowingInitialEmptyDocument()) ++ return false; ++ ++ // The method is called from WebPageProxy::initializePage and the ++ // target is not created yet (it is created after the new page is ++ // initialized and attached to the process). ++ return m_targetAgent->shouldPauseOnStart(); ++} ++ +void WebPageInspectorController::setContinueLoadingCallback(WTF::Function&& callback) +{ + auto* target = m_targets.get(WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess())); @@ -14426,7 +14210,7 @@ index e4f2f719746ed69b1226be2d47b16666f2067772..e94eba914cf44bad58c63be024a862d9 bool WebPageInspectorController::shouldPauseLoading(const ProvisionalPageProxy& provisionalPage) const { if (!m_frontendRouter->hasFrontends()) -@@ -203,7 +408,7 @@ void WebPageInspectorController::setContinueLoadingCallback(const ProvisionalPag +@@ -203,7 +424,7 @@ void WebPageInspectorController::setContinueLoadingCallback(const ProvisionalPag void WebPageInspectorController::didCreateProvisionalPage(ProvisionalPageProxy& provisionalPage) { @@ -14435,7 +14219,7 @@ index e4f2f719746ed69b1226be2d47b16666f2067772..e94eba914cf44bad58c63be024a862d9 } void WebPageInspectorController::willDestroyProvisionalPage(const ProvisionalPageProxy& provisionalPage) -@@ -287,4 +492,30 @@ void WebPageInspectorController::browserExtensionsDisabled(HashSet&& ext +@@ -287,4 +508,30 @@ void WebPageInspectorController::browserExtensionsDisabled(HashSet&& ext m_enabledBrowserAgent->extensionsDisabled(WTFMove(extensionIDs)); } @@ -14467,7 +14251,7 @@ index e4f2f719746ed69b1226be2d47b16666f2067772..e94eba914cf44bad58c63be024a862d9 + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h -index 29457fc3c76c963bf50b44c011f64398efbae676..999160e64365ad73e87601094b69a86224a2b54e 100644 +index 29457fc3c76c963bf50b44c011f64398efbae676..b931b09dbf2768bdfa49633fc6329fb49b09205a 100644 --- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h +++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h @@ -26,19 +26,43 @@ @@ -14491,7 +14275,7 @@ index 29457fc3c76c963bf50b44c011f64398efbae676..999160e64365ad73e87601094b69a862 +#include +#endif + -+#if USE(CAIRO) ++#if USE(CAIRO) || PLATFORM(GTK) +#include +#endif @@ -14560,7 +14344,7 @@ index 29457fc3c76c963bf50b44c011f64398efbae676..999160e64365ad73e87601094b69a862 bool hasLocalFrontend() const; -@@ -67,11 +122,29 @@ public: +@@ -67,11 +122,30 @@ public: #if ENABLE(REMOTE_INSPECTOR) void setIndicating(bool); #endif @@ -14584,13 +14368,14 @@ index 29457fc3c76c963bf50b44c011f64398efbae676..999160e64365ad73e87601094b69a862 + void setPauseOnStart(bool); + -+ bool shouldPauseLoading() const; ++ bool shouldPauseLoadRequest() const; ++ bool shouldPauseInInspectorWhenShown() const; + void setContinueLoadingCallback(WTF::Function&&); + bool shouldPauseLoading(const ProvisionalPageProxy&) const; void setContinueLoadingCallback(const ProvisionalPageProxy&, WTF::Function&&); -@@ -86,11 +159,12 @@ public: +@@ -86,11 +160,12 @@ public: void browserExtensionsDisabled(HashSet&&); private: @@ -14604,19 +14389,18 @@ index 29457fc3c76c963bf50b44c011f64398efbae676..999160e64365ad73e87601094b69a862 Ref m_frontendRouter; Ref m_backendDispatcher; -@@ -99,11 +173,17 @@ private: - WeakRef m_inspectedPage; - +@@ -101,9 +176,16 @@ private: CheckedPtr m_targetAgent; + HashMap> m_targets; + + WebPageInspectorEmulationAgent* m_emulationAgent { nullptr }; + WebPageInspectorInputAgent* m_inputAgent { nullptr }; + InspectorScreencastAgent* m_screecastAgent { nullptr }; - HashMap> m_targets; - ++ CheckedPtr m_enabledBrowserAgent; bool m_didCreateLazyAgents { false }; -+ HashMap m_pendingNavigations; ++ UncheckedKeyHashMap m_pendingNavigations; + + static WebPageInspectorControllerObserver* s_observer; }; @@ -14855,7 +14639,7 @@ index 0000000000000000000000000000000000000000..d0e11ed81a6257c011df23d5870da740 +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..a7a92f6d3730b64e1a8864158f6dbebbabc0b68c +index 0000000000000000000000000000000000000000..f7b2ecd583cd1eb5bb9e81becdfe07f5a855f2a9 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp @@ -0,0 +1,1006 @@ @@ -15239,7 +15023,7 @@ index 0000000000000000000000000000000000000000..a7a92f6d3730b64e1a8864158f6dbebb + + String browserContextID = toBrowserContextIDProtocolString(page.sessionID()); + String pageProxyID = toPageProxyIDProtocolString(page); -+ auto* opener = page.configuration().relatedPage(); ++ auto* opener = page.configuration().openerPageForInspector(); + String openerId; + if (opener) + openerId = toPageProxyIDProtocolString(*opener); @@ -15867,7 +15651,7 @@ index 0000000000000000000000000000000000000000..a7a92f6d3730b64e1a8864158f6dbebb +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h new file mode 100644 -index 0000000000000000000000000000000000000000..0a3b5a7604ec1abca5c2fff66b02ada96ddce4d1 +index 0000000000000000000000000000000000000000..2cd467df987e1679ff8918c2867bf253ce105b8c --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h @@ -0,0 +1,140 @@ @@ -16000,11 +15784,11 @@ index 0000000000000000000000000000000000000000..0a3b5a7604ec1abca5c2fff66b02ada9 + std::unique_ptr m_client; + std::unique_ptr m_frontendDispatcher; + Ref m_playwrightDispatcher; -+ HashMap> m_pageProxyChannels; ++ UncheckedKeyHashMap> m_pageProxyChannels; + BrowserContext* m_defaultContext; -+ HashMap> m_downloads; -+ HashMap> m_browserContexts; -+ HashMap> m_browserContextDeletions; ++ UncheckedKeyHashMap> m_downloads; ++ UncheckedKeyHashMap> m_browserContexts; ++ UncheckedKeyHashMap> m_browserContextDeletions; + bool m_isEnabled { false }; +}; + @@ -16091,10 +15875,10 @@ index 0000000000000000000000000000000000000000..e7a3dcc533294bb6e12f65d79b5b716b + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp b/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp -index 28a4d766b125615ec3111f4e42c0831bfb69e094..4f15f2335f56220da2fa50ff0ec61b6872d6fd3f 100644 +index e0c2996d93c2fe483024e13fb5b50a93a4e38150..6af596bd81076961f4e7e750d18c8b9dfd84f467 100644 --- a/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp +++ b/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp -@@ -176,6 +176,13 @@ void ProcessLauncher::launchProcess() +@@ -168,6 +168,13 @@ void ProcessLauncher::launchProcess() nargs++; } #endif @@ -16106,9 +15890,9 @@ index 28a4d766b125615ec3111f4e42c0831bfb69e094..4f15f2335f56220da2fa50ff0ec61b68 + } +// Playwright end - char** argv = g_newa(char*, nargs); - unsigned i = 0; -@@ -192,6 +199,10 @@ void ProcessLauncher::launchProcess() + WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN // GTK/WPE port + +@@ -186,6 +193,10 @@ void ProcessLauncher::launchProcess() if (configureJSCForTesting) argv[i++] = const_cast("--configure-jsc-for-testing"); #endif @@ -16118,7 +15902,7 @@ index 28a4d766b125615ec3111f4e42c0831bfb69e094..4f15f2335f56220da2fa50ff0ec61b68 +// Playwright end argv[i++] = nullptr; - // Warning: we want GIO to be able to spawn with posix_spawn() rather than fork()/exec(), in + WTF_ALLOW_UNSAFE_BUFFER_USAGE_END diff --git a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp b/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp index fac881d7c3d44758591d7a9f392a3992ce9f9a72..35eba5a0b31fc6e2d6e5c05c9f866c03d2e1c7d0 100644 --- a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp @@ -16146,20 +15930,8 @@ index fac881d7c3d44758591d7a9f392a3992ce9f9a72..35eba5a0b31fc6e2d6e5c05c9f866c03 PROCESS_INFORMATION processInformation { }; BOOL result = ::CreateProcess(0, commandLine.data(), 0, 0, true, 0, 0, 0, &startupInfo, &processInformation); -diff --git a/Source/WebKit/UIProcess/Media/RemoteMediaSessionCoordinatorProxy.cpp b/Source/WebKit/UIProcess/Media/RemoteMediaSessionCoordinatorProxy.cpp -index 1c2e1038c2a00264eebac03c1e89e6d5a5d247a0..714e4d09ab152330bc281e7c9e8e43e9131af27e 100644 ---- a/Source/WebKit/UIProcess/Media/RemoteMediaSessionCoordinatorProxy.cpp -+++ b/Source/WebKit/UIProcess/Media/RemoteMediaSessionCoordinatorProxy.cpp -@@ -30,6 +30,7 @@ - - #include "Logging.h" - #include "MediaSessionCoordinatorProxyPrivate.h" -+#include "MessageSenderInlines.h" - #include "RemoteMediaSessionCoordinatorMessages.h" - #include "RemoteMediaSessionCoordinatorProxyMessages.h" - #include "WebPageProxy.h" diff --git a/Source/WebKit/UIProcess/PageClient.h b/Source/WebKit/UIProcess/PageClient.h -index 960043d7db4e4898380e11300e73e6fe52c6da07..9a5cedfce7dfe331a71ecb10d4dc08845db512d6 100644 +index e978cabad88aeb44a8722f0df7eed9cff0320653..c1753b243bf51870aa4a1b3d3a1163bd8310596d 100644 --- a/Source/WebKit/UIProcess/PageClient.h +++ b/Source/WebKit/UIProcess/PageClient.h @@ -74,6 +74,11 @@ @@ -16184,10 +15956,10 @@ index 960043d7db4e4898380e11300e73e6fe52c6da07..9a5cedfce7dfe331a71ecb10d4dc0884 +#endif +#endif + - namespace WebKit { - class PageClient; - } -@@ -377,7 +388,20 @@ public: + namespace API { + class Attachment; + class HitTestResult; +@@ -373,7 +384,20 @@ public: virtual void selectionDidChange() = 0; #endif @@ -16335,7 +16107,7 @@ index 0000000000000000000000000000000000000000..3c8fd0549f1847515d35092f0f49b060 + +#endif // ENABLE(FULLSCREEN_API) diff --git a/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp b/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp -index 924718f62be57635f13afd3edb3f079906b31540..81d5cb24004311941063610aa4830d92fa3633bc 100644 +index 949c12f22544a17e9047def6f1ddf6a6e6fc1adc..bfd4d442f971e3956ed6d6962f7a570ff0a0755c 100644 --- a/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp +++ b/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp @@ -25,6 +25,7 @@ @@ -16348,10 +16120,10 @@ index 924718f62be57635f13afd3edb3f079906b31540..81d5cb24004311941063610aa4830d92 #include "ProvisionalFrameCreationParameters.h" diff --git a/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..1a824be7d9fcb225d018b4a821fa895e844d7805 +index 0000000000000000000000000000000000000000..b1ddac8c1442cb4da17f50d92599ef9aff6d4066 --- /dev/null +++ b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp -@@ -0,0 +1,225 @@ +@@ -0,0 +1,230 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * @@ -16384,6 +16156,7 @@ index 0000000000000000000000000000000000000000..1a824be7d9fcb225d018b4a821fa895e + +#include "InspectorPlaywrightAgent.h" +#include ++#include +#include +#include +#include @@ -16399,6 +16172,8 @@ index 0000000000000000000000000000000000000000..1a824be7d9fcb225d018b4a821fa895e +#include +#endif + ++WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN ++ +namespace WebKit { + +namespace { @@ -16577,6 +16352,8 @@ index 0000000000000000000000000000000000000000..1a824be7d9fcb225d018b4a821fa895e +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) ++ ++WTF_ALLOW_UNSAFE_BUFFER_USAGE_END diff --git a/Source/WebKit/UIProcess/RemoteInspectorPipe.h b/Source/WebKit/UIProcess/RemoteInspectorPipe.h new file mode 100644 index 0000000000000000000000000000000000000000..6d04f9290135069359ce6bf8726546482fd1dc95 @@ -16648,32 +16425,8 @@ index 0000000000000000000000000000000000000000..6d04f9290135069359ce6bf872654648 +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) -diff --git a/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteLayerTreeEventDispatcher.h b/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteLayerTreeEventDispatcher.h -index a91f8ca1dabd76b41632ea2d5d4223a7c657dc19..1c9de7acb15fa190a08ab4dc9d30772766a06989 100644 ---- a/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteLayerTreeEventDispatcher.h -+++ b/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteLayerTreeEventDispatcher.h -@@ -30,6 +30,7 @@ - #include "DisplayLinkObserverID.h" - #include "MomentumEventDispatcher.h" - #include "NativeWebWheelEvent.h" -+#include "RemoteLayerTreeNode.h" - #include - #include - #include -@@ -41,6 +42,11 @@ - #include - #include - #include -+#include -+#include -+ -+#include "NativeWebWheelEvent.h" -+#include "WebPage.h" - - namespace WebCore { - class PlatformWheelEvent; diff --git a/Source/WebKit/UIProcess/RemotePageProxy.cpp b/Source/WebKit/UIProcess/RemotePageProxy.cpp -index ba2898874c785f21fb68b77b5a15fd18ce9d68fd..9e0094660772ee3985b6f05700992104ba870e6d 100644 +index eae3ae7fdac55067463e1571068ec8cf25408bd9..707e9feec18d94c3a14b49e5826cab1026ff234a 100644 --- a/Source/WebKit/UIProcess/RemotePageProxy.cpp +++ b/Source/WebKit/UIProcess/RemotePageProxy.cpp @@ -44,6 +44,7 @@ @@ -16684,94 +16437,18 @@ index ba2898874c785f21fb68b77b5a15fd18ce9d68fd..9e0094660772ee3985b6f05700992104 #include #include -diff --git a/Source/WebKit/UIProcess/RemotePageProxy.h b/Source/WebKit/UIProcess/RemotePageProxy.h -index 9fef5ebf4661c8aa1df77907ff7c3f077c6bf001..e1ee1fd8ea17b03ca3fcedc8b5d920d67bf90373 100644 ---- a/Source/WebKit/UIProcess/RemotePageProxy.h -+++ b/Source/WebKit/UIProcess/RemotePageProxy.h -@@ -76,7 +76,6 @@ class WebProcessProxy; - - struct FrameInfoData; - struct FrameTreeCreationParameters; --struct NavigationActionData; - - class RemotePageProxy : public IPC::MessageReceiver { - WTF_MAKE_TZONE_ALLOCATED(RemotePageProxy); -diff --git a/Source/WebKit/UIProcess/WebAuthentication/fido/U2fAuthenticator.cpp b/Source/WebKit/UIProcess/WebAuthentication/fido/U2fAuthenticator.cpp -index 40531b866fda1c35dbddb90f2ac1027688b2a09c..82003f78d7d2c9fbf2d393187636cf8b0bcf228f 100644 ---- a/Source/WebKit/UIProcess/WebAuthentication/fido/U2fAuthenticator.cpp -+++ b/Source/WebKit/UIProcess/WebAuthentication/fido/U2fAuthenticator.cpp -@@ -37,6 +37,7 @@ - #include - #include - #include -+#include - - #define U2F_RELEASE_LOG(fmt, ...) RELEASE_LOG(WebAuthn, "%p [transport=%s] - U2fAuthenticator::" fmt, this, transportForDebugging().utf8().data(), ##__VA_ARGS__) - -diff --git a/Source/WebKit/UIProcess/WebContextMenuProxy.cpp b/Source/WebKit/UIProcess/WebContextMenuProxy.cpp -index 71fdc0b69e820af7f955482b42562e941eeac349..2a2d55e5a67aa7120193fd55913d3dbbbac62919 100644 ---- a/Source/WebKit/UIProcess/WebContextMenuProxy.cpp -+++ b/Source/WebKit/UIProcess/WebContextMenuProxy.cpp -@@ -33,6 +33,7 @@ - #include "WebPageMessages.h" - #include "WebPageProxy.h" - #include "WebProcessProxy.h" -+#include "MessageSenderInlines.h" - - namespace WebKit { - diff --git a/Source/WebKit/UIProcess/WebContextMenuProxy.h b/Source/WebKit/UIProcess/WebContextMenuProxy.h -index e2ded3c65b9680346be2534a3e970e2f425a83a8..b0c006c1dcbfae4b33530f8eae04f9868cd4d8b9 100644 +index c951d8577473371d8eb59ad651451737349c4389..b38cd0967ae45733a94594fd25900ddc1d49c3f6 100644 --- a/Source/WebKit/UIProcess/WebContextMenuProxy.h +++ b/Source/WebKit/UIProcess/WebContextMenuProxy.h -@@ -46,6 +46,7 @@ public: - virtual ~WebContextMenuProxy(); +@@ -49,6 +49,7 @@ public: + void deref() const final { RefCounted::deref(); } virtual void show(); + virtual void hide() {} WebPageProxy* page() const { return m_page.get(); } -diff --git a/Source/WebKit/UIProcess/WebFrameProxy.cpp b/Source/WebKit/UIProcess/WebFrameProxy.cpp -index 1cbf04be848366e881fd8ceec3de82628786548b..03ba18dcd9eb7b8c9ad95b5546adbcf2e8b76e4a 100644 ---- a/Source/WebKit/UIProcess/WebFrameProxy.cpp -+++ b/Source/WebKit/UIProcess/WebFrameProxy.cpp -@@ -31,6 +31,7 @@ - #include "Connection.h" - #include "DrawingAreaMessages.h" - #include "DrawingAreaProxy.h" -+#include "FormDataReference.h" - #include "FrameProcess.h" - #include "FrameTreeCreationParameters.h" - #include "FrameTreeNodeData.h" -@@ -42,6 +43,7 @@ - #include "RemotePageProxy.h" - #include "WebFramePolicyListenerProxy.h" - #include "WebNavigationState.h" -+#include "WebPageInspectorController.h" - #include "WebPageMessages.h" - #include "WebPageProxy.h" - #include "WebPageProxyMessages.h" -diff --git a/Source/WebKit/UIProcess/WebNavigationState.h b/Source/WebKit/UIProcess/WebNavigationState.h -index 26077dc941a14d58e6a07182d650abb48cc8b62c..77ed2b05ded42183b8274e46c69957f7b6dc2eae 100644 ---- a/Source/WebKit/UIProcess/WebNavigationState.h -+++ b/Source/WebKit/UIProcess/WebNavigationState.h -@@ -31,6 +31,7 @@ - #include - #include - #include -+#include "WebPageProxy.h" - - namespace WebKit { - class WebNavigationState; -@@ -54,7 +55,6 @@ enum class FrameLoadType : uint8_t; - - namespace WebKit { - --class WebPageProxy; - class WebBackForwardListItem; - - class WebNavigationState : public CanMakeWeakPtr { diff --git a/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a8d10ae990997684766df46719c65aa8dd77f28 @@ -16939,7 +16616,7 @@ index 0000000000000000000000000000000000000000..0a8d10ae990997684766df46719c65aa +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h new file mode 100644 -index 0000000000000000000000000000000000000000..b70bfe0411571f4d181a7fae3186aaae7cd7b831 +index 0000000000000000000000000000000000000000..d00d00ce8fd800dc1497b36b8a495c5b9aef6f58 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h @@ -0,0 +1,76 @@ @@ -17015,7 +16692,7 @@ index 0000000000000000000000000000000000000000..b70bfe0411571f4d181a7fae3186aaae + Ref m_backendDispatcher; + WebPageProxy& m_page; + Vector> m_commandsToRunWhenShown; -+ HashMap> m_permissions; ++ UncheckedKeyHashMap> m_permissions; +}; + +} // namespace WebKit @@ -17513,10 +17190,10 @@ index 0000000000000000000000000000000000000000..26a2a3c0791c334f811ec99a630314f8 + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp -index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf42681697b2ed14 100644 +index 963ca0b7a50c8ded555090c68aaa6acec526f7f9..0d9e4394824a664a35b10db392b913064f8ae471 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit/UIProcess/WebPageProxy.cpp -@@ -195,12 +195,14 @@ +@@ -199,12 +199,14 @@ #include #include #include @@ -17531,7 +17208,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 #include #include #include -@@ -222,6 +224,7 @@ +@@ -227,6 +229,7 @@ #include #include #include @@ -17539,7 +17216,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 #include #include #include -@@ -229,12 +232,15 @@ +@@ -234,10 +237,13 @@ #include #include #include @@ -17548,14 +17225,12 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 #include #include #include - #include ++#include +#include #include -+#include + #include #include - #include - #include -@@ -319,6 +325,9 @@ +@@ -324,6 +330,9 @@ #if USE(GBM) #include "AcceleratedBackingStoreDMABuf.h" #endif @@ -17565,7 +17240,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 #include #endif -@@ -443,6 +452,8 @@ static constexpr Seconds tryCloseTimeoutDelay = 50_ms; +@@ -452,6 +461,8 @@ static constexpr Seconds tryCloseTimeoutDelay = 50_ms; static constexpr Seconds audibleActivityClearDelay = 10_s; #endif @@ -17574,9 +17249,9 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageProxyCounter, ("WebPageProxy")); #if PLATFORM(COCOA) -@@ -868,6 +879,10 @@ WebPageProxy::~WebPageProxy() - if (preferences->mediaSessionCoordinatorEnabled()) - GroupActivitiesSessionNotifier::singleton().removeWebPage(*this); +@@ -939,6 +950,10 @@ WebPageProxy::~WebPageProxy() + if (RefPtr gpuProcess = GPUProcessProxy::singletonIfCreated()) + gpuProcess->setPresentingApplicationAuditToken(m_legacyMainFrameProcess->coreProcessIdentifier(), m_webPageID, std::nullopt); #endif + +#if PLATFORM(COCOA) @@ -17585,25 +17260,25 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 } Ref WebPageProxy::Internals::protectedPage() const -@@ -1429,6 +1444,7 @@ void WebPageProxy::finishAttachingToWebProcess(const Site& site, ProcessLaunchRe +@@ -1515,6 +1530,7 @@ void WebPageProxy::finishAttachingToWebProcess(const Site& site, ProcessLaunchRe if (RefPtr pageClient = this->pageClient()) pageClient->didRelaunchProcess(); - internals().pageLoadState.didSwapWebProcesses(); + protectedPageLoadState()->didSwapWebProcesses(); + m_inspectorController->didFinishAttachingToWebProcess(); } void WebPageProxy::didAttachToRunningProcess() -@@ -1437,7 +1453,7 @@ void WebPageProxy::didAttachToRunningProcess() +@@ -1523,7 +1539,7 @@ void WebPageProxy::didAttachToRunningProcess() #if ENABLE(FULLSCREEN_API) ASSERT(!m_fullScreenManager); -- m_fullScreenManager = makeUnique(*this, protectedPageClient()->fullScreenManagerProxyClient()); -+ m_fullScreenManager = makeUnique(*this, m_fullScreenManagerClientOverride ? *m_fullScreenManagerClientOverride : protectedPageClient()->fullScreenManagerProxyClient()); +- m_fullScreenManager = WebFullScreenManagerProxy::create(*this, protectedPageClient()->fullScreenManagerProxyClient()); ++ m_fullScreenManager = WebFullScreenManagerProxy::create(*this, m_fullScreenManagerClientOverride ? *m_fullScreenManagerClientOverride : protectedPageClient()->fullScreenManagerProxyClient()); #endif #if ENABLE(VIDEO_PRESENTATION_MODE) ASSERT(!m_playbackSessionManager); -@@ -1877,6 +1893,21 @@ WebProcessProxy& WebPageProxy::ensureRunningProcess() - return m_legacyMainFrameProcess; +@@ -1989,6 +2005,21 @@ Ref WebPageProxy::ensureProtectedRunningProcess() + return ensureRunningProcess(); } +RefPtr WebPageProxy::loadRequestForInspector(WebCore::ResourceRequest&& request, WebFrameProxy* frame) @@ -17621,11 +17296,45 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 + return navigation; +} + - RefPtr WebPageProxy::loadRequest(ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, IsPerformingHTTPFallback isPerformingHTTPFallback, API::Object* userData) + RefPtr WebPageProxy::loadRequest(WebCore::ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, IsPerformingHTTPFallback isPerformingHTTPFallback, std::unique_ptr&& lastNavigationAction, API::Object* userData) { if (m_isClosed) -@@ -2507,6 +2538,61 @@ void WebPageProxy::setControlledByAutomation(bool controlled) - websiteDataStore().protectedNetworkProcess()->send(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation), 0); +@@ -2086,11 +2117,29 @@ void WebPageProxy::loadRequestWithNavigationShared(Ref&& proces + + navigation->setIsLoadedWithNavigationShared(true); + protectedProcess->markProcessAsRecentlyUsed(); +- if (!protectedProcess->isLaunching() || !url.protocolIsFile()) +- protectedProcess->send(Messages::WebPage::LoadRequest(WTFMove(loadParameters)), webPageID); ++ ++ // Pause loading for new window navigation. ++ Function continuation = [ ++ weakThis = WeakPtr { protectedThis }, ++ weakProcess = WeakPtr { protectedProcess }, ++ loadParameters = WTFMove(loadParameters), ++ webPageID, ++ url ++ ]() mutable { ++ RefPtr innerProtectedProcess = weakProcess.get(); ++ RefPtr innerProtectedThis = weakThis.get(); ++ if (!innerProtectedProcess || !innerProtectedThis) ++ return; ++ if (!innerProtectedProcess->isLaunching() || !url.protocolIsFile()) ++ innerProtectedProcess->send(Messages::WebPage::LoadRequest(WTFMove(loadParameters)), webPageID); ++ else ++ innerProtectedProcess->send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(WTFMove(loadParameters), innerProtectedThis->internals().pageLoadState.resourceDirectoryURL(), innerProtectedThis->identifier(), true), webPageID); ++ innerProtectedProcess->startResponsivenessTimer(); ++ }; ++ if (protectedThis->m_inspectorController->shouldPauseLoadRequest()) ++ protectedThis->m_inspectorController->setContinueLoadingCallback(WTFMove(continuation)); + else +- protectedProcess->send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(WTFMove(loadParameters), protectedThis->pageLoadState().resourceDirectoryURL(), protectedThis->identifier(), true), webPageID); +- protectedProcess->startResponsivenessTimer(); ++ continuation(); + }); + } + +@@ -2634,6 +2683,61 @@ void WebPageProxy::setControlledByAutomation(bool controlled) + protectedWebsiteDataStore()->protectedNetworkProcess()->send(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation), 0); } +void WebPageProxy::setAuthCredentialsForAutomation(std::optional&& credentials, std::optional&& origin) @@ -17634,7 +17343,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 + m_authOriginForAutomation = WTFMove(origin); +} + -+void WebPageProxy::setPermissionsForAutomation(const HashMap>& permissions) ++void WebPageProxy::setPermissionsForAutomation(const UncheckedKeyHashMap>& permissions) +{ + m_permissionsForAutomation = permissions; +} @@ -17686,7 +17395,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 void WebPageProxy::createInspectorTarget(IPC::Connection& connection, const String& targetId, Inspector::InspectorTargetType type) { MESSAGE_CHECK_BASE(!targetId.isEmpty(), connection); -@@ -2756,6 +2842,24 @@ void WebPageProxy::updateActivityState(OptionSet flagsToUpdate) +@@ -2886,6 +2990,24 @@ void WebPageProxy::updateActivityState(OptionSet flagsToUpdate) bool wasVisible = isViewVisible(); RefPtr pageClient = this->pageClient(); internals().activityState.remove(flagsToUpdate); @@ -17711,7 +17420,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 if (flagsToUpdate & ActivityState::IsFocused && pageClient->isViewFocused()) internals().activityState.add(ActivityState::IsFocused); if (flagsToUpdate & ActivityState::WindowIsActive && pageClient->isViewWindowActive()) -@@ -3522,7 +3626,7 @@ void WebPageProxy::performDragOperation(DragData& dragData, const String& dragSt +@@ -3654,7 +3776,7 @@ void WebPageProxy::performDragOperation(DragData& dragData, const String& dragSt if (!hasRunningProcess()) return; @@ -17720,7 +17429,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 URL url { dragData.asURL() }; if (url.protocolIsFile()) protectedLegacyMainFrameProcess()->assumeReadAccessToBaseURL(*this, url.string(), [] { }); -@@ -3550,6 +3654,8 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag +@@ -3682,6 +3804,8 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag if (!hasRunningProcess()) return; @@ -17729,7 +17438,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 auto completionHandler = [this, protectedThis = Ref { *this }, action, dragData] (std::optional dragOperation, WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect, const IntRect& editableElementRect, std::optional remoteUserInputEventData) mutable { if (!m_pageClient) return; -@@ -3561,7 +3667,7 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag +@@ -3693,7 +3817,7 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag dragData.setClientPosition(remoteUserInputEventData->transformedPoint); performDragControllerAction(action, dragData, remoteUserInputEventData->targetFrameID); }; @@ -17738,7 +17447,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 ASSERT(dragData.platformData()); sendWithAsyncReplyToProcessContainingFrame(frameID, Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), *dragData.platformData(), dragData.flags()), WTFMove(completionHandler)); #else -@@ -3595,14 +3701,35 @@ void WebPageProxy::didPerformDragControllerAction(std::optionalpageClient()) pageClient->didPerformDragControllerAction(); @@ -17778,7 +17487,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 } didStartDrag(); } -@@ -3624,6 +3751,24 @@ void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& glo +@@ -3757,6 +3902,24 @@ void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& glo setDragCaretRect({ }); } @@ -17803,7 +17512,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 void WebPageProxy::didStartDrag() { if (!hasRunningProcess()) -@@ -3631,6 +3776,26 @@ void WebPageProxy::didStartDrag() +@@ -3764,6 +3927,26 @@ void WebPageProxy::didStartDrag() discardQueuedMouseEvents(); send(Messages::WebPage::DidStartDrag()); @@ -17830,7 +17539,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 } void WebPageProxy::dragCancelled() -@@ -3778,26 +3943,47 @@ void WebPageProxy::processNextQueuedMouseEvent() +@@ -3911,26 +4094,47 @@ void WebPageProxy::processNextQueuedMouseEvent() process->startResponsivenessTimer(); } @@ -17890,25 +17599,25 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 } void WebPageProxy::doAfterProcessingAllPendingMouseEvents(WTF::Function&& action) -@@ -3965,6 +4151,8 @@ void WebPageProxy::wheelEventHandlingCompleted(bool wasHandled) +@@ -4099,6 +4303,8 @@ void WebPageProxy::wheelEventHandlingCompleted(bool wasHandled) - if (RefPtr automationSession = configuration().processPool().automationSession()) + if (RefPtr automationSession = protectedConfiguration()->processPool().automationSession()) automationSession->wheelEventsFlushedForPage(*this); + + m_inspectorController->didProcessAllPendingWheelEvents(); } void WebPageProxy::cacheWheelEventScrollingAccelerationCurve(const NativeWebWheelEvent& nativeWheelEvent) -@@ -4100,7 +4288,7 @@ static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b) +@@ -4234,7 +4440,7 @@ static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b) void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent) { -#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA) +#if ENABLE(ASYNC_SCROLLING) && PLATFORM(IOS_FAMILY) for (auto& touchPoint : touchStartEvent.touchPoints()) { - auto location = touchPoint.location(); + auto location = touchPoint.locationInRootView(); auto update = [this, location](TrackingType& trackingType, EventTrackingRegions::EventType eventType) { -@@ -4723,6 +4911,7 @@ void WebPageProxy::receivedNavigationActionPolicyDecision(WebProcessProxy& proce +@@ -4861,6 +5067,7 @@ void WebPageProxy::receivedNavigationActionPolicyDecision(WebProcessProxy& proce void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, RefPtr&& websitePolicies, Ref&& navigationAction, WillContinueLoadInNewProcess willContinueLoadInNewProcess, std::optional sandboxExtensionHandle, std::optional&& consoleMessage, CompletionHandler&& completionHandler) { @@ -17916,28 +17625,23 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 if (!hasRunningProcess()) return completionHandler(PolicyDecision { }); -@@ -5671,6 +5860,12 @@ void WebPageProxy::pageScaleFactorDidChange(IPC::Connection& connection, double - m_pageScaleFactor = scaleFactor; - } - -+void WebPageProxy::viewScaleFactorDidChange(IPC::Connection& connection, double scaleFactor) -+{ -+ MESSAGE_CHECK_BASE(scaleFactorIsValid(scaleFactor), connection); +@@ -5857,6 +6064,7 @@ void WebPageProxy::viewScaleFactorDidChange(IPC::Connection& connection, double + MESSAGE_CHECK_BASE(scaleFactorIsValid(scaleFactor), connection); + if (!legacyMainFrameProcess().hasConnection(connection)) + return; + m_viewScaleFactor = scaleFactor; -+} -+ - void WebPageProxy::pluginScaleFactorDidChange(IPC::Connection& connection, double pluginScaleFactor) - { - MESSAGE_CHECK_BASE(scaleFactorIsValid(pluginScaleFactor), connection); -@@ -6283,6 +6478,7 @@ void WebPageProxy::didDestroyNavigationShared(Ref&& process, We + + forEachWebContentProcess([&] (auto& process, auto pageID) { + if (&process == &legacyMainFrameProcess()) +@@ -6518,6 +6726,7 @@ void WebPageProxy::didDestroyNavigationShared(Ref&& process, We RefPtr protectedPageClient { pageClient() }; - m_navigationState->didDestroyNavigation(process->coreProcessIdentifier(), navigationID); + protectedNavigationState()->didDestroyNavigation(process->coreProcessIdentifier(), navigationID); + m_inspectorController->didDestroyNavigation(navigationID); } void WebPageProxy::didStartProvisionalLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, std::optional navigationID, URL&& url, URL&& unreachableURL, const UserData& userData, WallTime timestamp) -@@ -6603,6 +6799,8 @@ void WebPageProxy::didFailProvisionalLoadForFrameShared(Ref&& p +@@ -6852,6 +7061,8 @@ void WebPageProxy::didFailProvisionalLoadForFrameShared(Ref&& p m_failingProvisionalLoadURL = { }; @@ -17946,15 +17650,26 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 // If the provisional page's load fails then we destroy the provisional page. if (m_provisionalPage && m_provisionalPage->mainFrame() == &frame && willContinueLoading == WillContinueLoading::No) m_provisionalPage = nullptr; -@@ -7966,6 +8164,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w +@@ -8271,8 +8482,9 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w if (RefPtr page = originatingFrameInfo->page()) openerAppInitiatedState = page->lastNavigationWasAppInitiated(); +- auto navigationDataForNewProcess = navigationActionData.hasOpener ? nullptr : makeUnique(navigationActionData); + m_inspectorController->willCreateNewPage(windowFeatures, request.url()); + ++ auto navigationDataForNewProcess = navigationActionData.hasOpener ? nullptr : makeUnique(navigationActionData); auto completionHandler = [ this, protectedThis = Ref { *this }, -@@ -8043,6 +8242,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w +@@ -8341,6 +8553,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w + configuration->setInitialSandboxFlags(effectiveSandboxFlags); + configuration->setWindowFeatures(WTFMove(windowFeatures)); + configuration->setOpenedMainFrameName(openedMainFrameName); ++ configuration->setOpenerPageForInspector(*this); + + if (RefPtr openerFrame = WebFrameProxy::webFrame(originatingFrameInfoData.frameID); navigationActionData.hasOpener && openerFrame) { + configuration->setRelatedPage(*this); +@@ -8365,6 +8578,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w void WebPageProxy::showPage() { m_uiClient->showPage(this); @@ -17962,7 +17677,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 } bool WebPageProxy::hasOpenedPage() const -@@ -8157,6 +8357,10 @@ void WebPageProxy::closePage() +@@ -8479,6 +8693,10 @@ void WebPageProxy::closePage() if (isClosed()) return; @@ -17973,7 +17688,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 WEBPAGEPROXY_RELEASE_LOG(Process, "closePage:"); if (RefPtr pageClient = this->pageClient()) pageClient->clearAllEditCommands(); -@@ -8194,6 +8398,8 @@ void WebPageProxy::runJavaScriptAlert(IPC::Connection& connection, FrameIdentifi +@@ -8517,6 +8735,8 @@ void WebPageProxy::runJavaScriptAlert(IPC::Connection& connection, FrameIdentifi } runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler&& completion) mutable { @@ -17982,7 +17697,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 page.m_uiClient->runJavaScriptAlert(page, message, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)]() mutable { reply(); completion(); -@@ -8215,6 +8421,8 @@ void WebPageProxy::runJavaScriptConfirm(IPC::Connection& connection, FrameIdenti +@@ -8539,6 +8759,8 @@ void WebPageProxy::runJavaScriptConfirm(IPC::Connection& connection, FrameIdenti if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this); } @@ -17991,7 +17706,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler&& completion) mutable { page.m_uiClient->runJavaScriptConfirm(page, message, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](bool result) mutable { -@@ -8238,6 +8446,8 @@ void WebPageProxy::runJavaScriptPrompt(IPC::Connection& connection, FrameIdentif +@@ -8563,6 +8785,8 @@ void WebPageProxy::runJavaScriptPrompt(IPC::Connection& connection, FrameIdentif if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this); } @@ -18000,7 +17715,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply), defaultValue](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler&& completion) mutable { page.m_uiClient->runJavaScriptPrompt(page, message, defaultValue, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](auto& result) mutable { -@@ -8366,6 +8576,8 @@ void WebPageProxy::runBeforeUnloadConfirmPanel(IPC::Connection& connection, Fram +@@ -8692,6 +8916,8 @@ void WebPageProxy::runBeforeUnloadConfirmPanel(IPC::Connection& connection, Fram return; } } @@ -18009,7 +17724,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 // Since runBeforeUnloadConfirmPanel() can spin a nested run loop we need to turn off the responsiveness timer and the tryClose timer. protectedLegacyMainFrameProcess()->stopResponsivenessTimer(); -@@ -8936,6 +9148,11 @@ void WebPageProxy::resourceLoadDidCompleteWithError(ResourceLoadInfo&& loadInfo, +@@ -9260,6 +9486,11 @@ void WebPageProxy::resourceLoadDidCompleteWithError(ResourceLoadInfo&& loadInfo, } #if ENABLE(FULLSCREEN_API) @@ -18021,7 +17736,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 WebFullScreenManagerProxy* WebPageProxy::fullScreenManager() { return m_fullScreenManager.get(); -@@ -9041,6 +9258,17 @@ void WebPageProxy::requestDOMPasteAccess(DOMPasteAccessCategory pasteAccessCateg +@@ -9370,6 +9601,17 @@ void WebPageProxy::requestDOMPasteAccess(IPC::Connection& connection, DOMPasteAc } } @@ -18039,7 +17754,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 m_pageClient->requestDOMPasteAccess(pasteAccessCategory, requiresInteraction, elementRect, originIdentifier, WTFMove(completionHandler)); } -@@ -9979,6 +10207,8 @@ void WebPageProxy::mouseEventHandlingCompleted(std::optional event +@@ -10400,6 +10642,8 @@ void WebPageProxy::mouseEventHandlingCompleted(std::optional event if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->mouseEventsFlushedForPage(*this); didFinishProcessingAllPendingMouseEvents(); @@ -18048,7 +17763,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 } } -@@ -10014,6 +10244,7 @@ void WebPageProxy::keyEventHandlingCompleted(std::optional eventTy +@@ -10434,6 +10678,7 @@ void WebPageProxy::keyEventHandlingCompleted(std::optional eventTy if (!canProcessMoreKeyEvents) { if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->keyboardEventsFlushedForPage(*this); @@ -18056,9 +17771,9 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 } } -@@ -10431,7 +10662,10 @@ void WebPageProxy::dispatchProcessDidTerminate(ProcessTerminationReason reason) - { - WEBPAGEPROXY_RELEASE_LOG_ERROR(Loading, "dispatchProcessDidTerminate: reason=%" PUBLIC_LOG_STRING, processTerminationReasonToString(reason).characters()); +@@ -10857,7 +11102,10 @@ void WebPageProxy::dispatchProcessDidTerminate(WebProcessProxy& process, Process + if (m_preferences->siteIsolationEnabled()) + m_browsingContextGroup->processDidTerminate(*this, process); - bool handledByClient = false; + bool handledByClient = m_inspectorController->pageCrashed(reason); @@ -18068,16 +17783,16 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 if (m_loaderClient) handledByClient = reason != ProcessTerminationReason::RequestedByClient && m_loaderClient->processDidCrash(*this); else -@@ -11065,6 +11299,8 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc +@@ -11513,6 +11761,8 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc - parameters.httpsUpgradeEnabled = preferences().upgradeKnownHostsToHTTPSEnabled() ? m_configuration->httpsUpgradeEnabled() : false; + parameters.httpsUpgradeEnabled = preferences->upgradeKnownHostsToHTTPSEnabled() ? configuration->httpsUpgradeEnabled() : false; -+ parameters.shouldPauseInInspectorWhenShown = m_inspectorController->shouldPauseLoading(); ++ parameters.shouldPauseInInspectorWhenShown = m_inspectorController->shouldPauseInInspectorWhenShown(); + #if PLATFORM(IOS) || PLATFORM(VISION) // FIXME: This is also being passed over the to WebProcess via the PreferencesStore. parameters.allowsDeprecatedSynchronousXMLHttpRequestDuringUnload = allowsDeprecatedSynchronousXMLHttpRequestDuringUnload(); -@@ -11229,8 +11465,42 @@ void WebPageProxy::allowGamepadAccess() +@@ -11676,8 +11926,42 @@ void WebPageProxy::allowGamepadAccess() #endif // ENABLE(GAMEPAD) @@ -18120,7 +17835,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 if (negotiatedLegacyTLS == NegotiatedLegacyTLS::Yes) { m_navigationClient->shouldAllowLegacyTLS(*this, authenticationChallenge.get(), [this, protectedThis = Ref { *this }, authenticationChallenge] (bool shouldAllowLegacyTLS) { if (shouldAllowLegacyTLS) -@@ -11324,6 +11594,12 @@ void WebPageProxy::requestGeolocationPermissionForFrame(IPC::Connection& connect +@@ -11772,6 +12056,12 @@ void WebPageProxy::requestGeolocationPermissionForFrame(IPC::Connection& connect request->deny(); }; @@ -18133,7 +17848,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 // FIXME: Once iOS migrates to the new WKUIDelegate SPI, clean this up // and make it one UIClient call that calls the completionHandler with false // if there is no delegate instead of returning the completionHandler -@@ -11386,6 +11662,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi +@@ -11834,6 +12124,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi shouldChangeDeniedToPrompt = false; if (sessionID().isEphemeral()) { @@ -18146,7 +17861,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 completionHandler(shouldChangeDeniedToPrompt ? PermissionState::Prompt : PermissionState::Denied); return; } -@@ -11400,6 +11682,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi +@@ -11848,6 +12144,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi return; } @@ -18160,7 +17875,7 @@ index dc95df8cd29f53622308310d998c3659a0190a71..f11fde5085cd28fe011372dcdf426816 completionHandler(shouldChangeDeniedToPrompt ? PermissionState::Prompt : PermissionState::Denied); return; diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h -index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61bdef5c20e 100644 +index b2c03a83961ca2dca8510461ab73693295f3c50a..94e859353dc61017f13d39227d256d6c97515422 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.h +++ b/Source/WebKit/UIProcess/WebPageProxy.h @@ -26,6 +26,7 @@ @@ -18169,9 +17884,9 @@ index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61b #include "APIObject.h" +#include "APIWebsitePolicies.h" #include "MessageReceiver.h" + #include #include - #include -@@ -38,6 +39,20 @@ +@@ -42,6 +43,20 @@ #include #include #include @@ -18192,15 +17907,15 @@ index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61b #if USE(DICTATION_ALTERNATIVES) #include -@@ -119,6 +134,7 @@ class DragData; +@@ -126,6 +141,7 @@ class DragData; class Exception; class FloatPoint; class FloatQuad; -+typedef HashMap> DragDataMap; ++typedef UncheckedKeyHashMap> DragDataMap; class FloatRect; class FloatSize; class FontAttributeChanges; -@@ -461,6 +477,7 @@ class WebExtensionController; +@@ -474,6 +490,7 @@ class WebExtensionController; class WebFramePolicyListenerProxy; class WebFrameProxy; class WebFullScreenManagerProxy; @@ -18208,7 +17923,7 @@ index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61b class WebInspectorUIProxy; class WebKeyboardEvent; class WebMouseEvent; -@@ -684,6 +701,8 @@ public: +@@ -707,6 +724,8 @@ public: void setControlledByAutomation(bool); WebPageInspectorController& inspectorController() { return *m_inspectorController; } @@ -18217,7 +17932,7 @@ index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61b #if PLATFORM(IOS_FAMILY) void showInspectorIndication(); -@@ -717,6 +736,7 @@ public: +@@ -741,6 +760,7 @@ public: bool hasSleepDisabler() const; #if ENABLE(FULLSCREEN_API) @@ -18225,28 +17940,29 @@ index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61b WebFullScreenManagerProxy* fullScreenManager(); API::FullscreenClient& fullscreenClient() const { return *m_fullscreenClient; } -@@ -805,6 +825,12 @@ public: +@@ -830,6 +850,12 @@ public: - void setPageLoadStateObserver(std::unique_ptr&&); + void setPageLoadStateObserver(RefPtr&&); + void setAuthCredentialsForAutomation(std::optional&&, std::optional&&); -+ void setPermissionsForAutomation(const HashMap>&); ++ void setPermissionsForAutomation(const UncheckedKeyHashMap>&); + void setOrientationOverride(std::optional&& angle); + void setActiveForAutomation(std::optional active); + void logToStderr(const String& str); + void initializeWebPage(const WebCore::Site&, WebCore::SandboxFlags); - void setDrawingArea(std::unique_ptr&&); + void setDrawingArea(RefPtr&&); + +@@ -861,6 +887,8 @@ public: + RefPtr loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, WebCore::IsPerformingHTTPFallback); + RefPtr loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, WebCore::IsPerformingHTTPFallback, std::unique_ptr&&, API::Object* userData = nullptr); -@@ -832,6 +858,7 @@ public: - RefPtr loadRequest(WebCore::ResourceRequest&&); - RefPtr loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy); - RefPtr loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, WebCore::IsPerformingHTTPFallback, API::Object* userData = nullptr); + RefPtr loadRequestForInspector(WebCore::ResourceRequest&&, WebFrameProxy*); ++ RefPtr loadFile(const String& fileURL, const String& resourceDirectoryURL, bool isAppInitiated = true, API::Object* userData = nullptr); RefPtr loadData(Ref&&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData = nullptr); RefPtr loadData(Ref&&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, WebCore::ShouldOpenExternalURLsPolicy); -@@ -898,6 +925,7 @@ public: +@@ -944,6 +972,7 @@ public: PageClient* pageClient() const; RefPtr protectedPageClient() const; @@ -18254,15 +17970,7 @@ index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61b void setViewNeedsDisplay(const WebCore::Region&); void requestScroll(const WebCore::FloatPoint& scrollPosition, const WebCore::IntPoint& scrollOrigin, WebCore::ScrollIsAnimated); -@@ -1427,6 +1455,7 @@ public: - #endif - - void pageScaleFactorDidChange(IPC::Connection&, double); -+ void viewScaleFactorDidChange(IPC::Connection&, double); - void pluginScaleFactorDidChange(IPC::Connection&, double); - void pluginZoomFactorDidChange(IPC::Connection&, double); - -@@ -1511,14 +1540,20 @@ public: +@@ -1566,14 +1595,20 @@ public: void didStartDrag(); void dragCancelled(); void setDragCaretRect(const WebCore::IntRect&); @@ -18284,7 +17992,7 @@ index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61b #endif void processDidBecomeUnresponsive(); -@@ -1757,6 +1792,7 @@ public: +@@ -1822,6 +1857,7 @@ public: void setViewportSizeForCSSViewportUnits(const WebCore::FloatSize&); WebCore::FloatSize viewportSizeForCSSViewportUnits() const; @@ -18292,7 +18000,7 @@ index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61b void didReceiveAuthenticationChallengeProxy(Ref&&, NegotiatedLegacyTLS); void negotiatedLegacyTLS(); void didNegotiateModernTLS(const URL&); -@@ -1790,6 +1826,8 @@ public: +@@ -1855,6 +1891,8 @@ public: #if PLATFORM(COCOA) || PLATFORM(GTK) RefPtr takeViewSnapshot(std::optional&&); RefPtr takeViewSnapshot(std::optional&&, ForceSoftwareCapturingViewportSnapshot); @@ -18301,7 +18009,7 @@ index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61b #endif void wrapCryptoKey(Vector&&, CompletionHandler>&&)>&&); -@@ -2722,6 +2760,7 @@ private: +@@ -2835,6 +2873,7 @@ private: RefPtr launchProcessForReload(); void requestNotificationPermission(const String& originString, CompletionHandler&&); @@ -18309,18 +18017,18 @@ index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61b void didChangeContentSize(const WebCore::IntSize&); void didChangeIntrinsicContentSize(const WebCore::IntSize&); -@@ -3237,8 +3276,10 @@ private: - String m_overrideContentSecurityPolicy; +@@ -3362,8 +3401,10 @@ private: + String m_openedMainFrameName; RefPtr m_inspector; + InspectorDialogAgent* m_inspectorDialogAgent { nullptr }; #if ENABLE(FULLSCREEN_API) + std::unique_ptr m_fullScreenManagerClientOverride; - std::unique_ptr m_fullScreenManager; + RefPtr m_fullScreenManager; std::unique_ptr m_fullscreenClient; #endif -@@ -3433,6 +3474,22 @@ private: +@@ -3562,6 +3603,22 @@ private: std::optional m_currentDragOperation; bool m_currentDragIsOverFileInput { false }; unsigned m_currentDragNumberOfFilesToBeAccepted { 0 }; @@ -18343,38 +18051,30 @@ index 22132a82fb63a08f4f18a9b7b915d81f930429c8..880a013168f401f85aa1215a0fd0f61b #endif bool m_mainFrameHasHorizontalScrollbar { false }; -@@ -3604,6 +3661,10 @@ private: +@@ -3735,6 +3792,10 @@ private: RefPtr messageBody; }; Vector m_pendingInjectedBundleMessages; + std::optional m_credentialsForAutomation; + std::optional m_authOriginForAutomation; -+ HashMap> m_permissionsForAutomation; ++ UncheckedKeyHashMap> m_permissionsForAutomation; + std::optional m_activeForAutomation; #if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION) - std::unique_ptr m_webDeviceOrientationUpdateProviderProxy; + RefPtr m_webDeviceOrientationUpdateProviderProxy; diff --git a/Source/WebKit/UIProcess/WebPageProxy.messages.in b/Source/WebKit/UIProcess/WebPageProxy.messages.in -index d5a3dbad2866cfb6980f2f47764eba902be9b60c..4872ea89b4d92649cef4681685239cf49b2bb30e 100644 +index 68e7c4024aa81d9339c4d62feae9f6270af46db8..c312f7c5d9d06893f2dad30c87968fe5dffd880d 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.messages.in +++ b/Source/WebKit/UIProcess/WebPageProxy.messages.in -@@ -30,6 +30,7 @@ messages -> WebPageProxy { +@@ -35,6 +35,7 @@ messages -> WebPageProxy { RunJavaScriptConfirm(WebCore::FrameIdentifier frameID, struct WebKit::FrameInfoData frameInfo, String message) -> (bool result) Synchronous RunJavaScriptPrompt(WebCore::FrameIdentifier frameID, struct WebKit::FrameInfoData frameInfo, String message, String defaultValue) -> (String result) Synchronous MouseDidMoveOverElement(struct WebKit::WebHitTestResultData hitTestResultData, OptionSet modifiers, WebKit::UserData userData) + LogToStderr(String text) - DidChangeViewportProperties(struct WebCore::ViewportAttributes attributes) DidReceiveEvent(enum:uint8_t WebKit::WebEventType eventType, bool handled, struct std::optional remoteUserInputEventData) -@@ -186,6 +187,7 @@ messages -> WebPageProxy { - #endif - - PageScaleFactorDidChange(double scaleFactor) -+ ViewScaleFactorDidChange(double scaleFactor) - PluginScaleFactorDidChange(double zoomFactor) - PluginZoomFactorDidChange(double zoomFactor) - -@@ -316,10 +318,14 @@ messages -> WebPageProxy { + SetCursor(WebCore::Cursor cursor) +@@ -330,10 +331,14 @@ messages -> WebPageProxy { StartDrag(struct WebCore::DragItem dragItem, WebCore::ShareableBitmapHandle dragImage) SetPromisedDataForImage(String pasteboardName, WebCore::SharedMemory::Handle imageHandle, String filename, String extension, String title, String url, String visibleURL, WebCore::SharedMemory::Handle archiveHandle, String originIdentifier) #endif @@ -18384,14 +18084,14 @@ index d5a3dbad2866cfb6980f2f47764eba902be9b60c..4872ea89b4d92649cef4681685239cf4 #endif +#if PLATFORM(WIN) && ENABLE(DRAG_SUPPORT) -+ StartDrag(HashMap> dragDataMap) ++ StartDrag(UncheckedKeyHashMap> dragDataMap) +#endif + #if PLATFORM(IOS_FAMILY) && ENABLE(DRAG_SUPPORT) DidHandleDragStartRequest(bool started) DidHandleAdditionalDragItemsRequest(bool added) diff --git a/Source/WebKit/UIProcess/WebProcessCache.cpp b/Source/WebKit/UIProcess/WebProcessCache.cpp -index 0bf66ef96022b16fe27cff481b41ebb369b5803a..9e3092647e880a75f7df26c361e220b8c89a603e 100644 +index 7211efa3028a16e070059251cd35cefa886f5d43..7aeab506c527d5ddcfa7f1e56749dca87ab7738e 100644 --- a/Source/WebKit/UIProcess/WebProcessCache.cpp +++ b/Source/WebKit/UIProcess/WebProcessCache.cpp @@ -92,6 +92,10 @@ bool WebProcessCache::canCacheProcess(WebProcessProxy& process) const @@ -18406,10 +18106,10 @@ index 0bf66ef96022b16fe27cff481b41ebb369b5803a..9e3092647e880a75f7df26c361e220b8 } diff --git a/Source/WebKit/UIProcess/WebProcessPool.cpp b/Source/WebKit/UIProcess/WebProcessPool.cpp -index b5a8f1b2da36d5c53d46d3b6e0a63e34d41db5d3..4df997597541f123cbd3f7e0b2016a26223b9b8e 100644 +index ab6e3d2220d2f02cce66a47ab0e2432685d0ce94..d5ec0bdb2b92137222a58ae3afda1e2dc5caca6b 100644 --- a/Source/WebKit/UIProcess/WebProcessPool.cpp +++ b/Source/WebKit/UIProcess/WebProcessPool.cpp -@@ -439,10 +439,10 @@ void WebProcessPool::setAutomationClient(std::unique_ptr& +@@ -444,10 +444,10 @@ void WebProcessPool::setAutomationClient(std::unique_ptr& void WebProcessPool::setOverrideLanguages(Vector&& languages) { @@ -18422,7 +18122,7 @@ index b5a8f1b2da36d5c53d46d3b6e0a63e34d41db5d3..4df997597541f123cbd3f7e0b2016a26 #if ENABLE(GPU_PROCESS) if (RefPtr gpuProcess = GPUProcessProxy::singletonIfCreated()) -@@ -450,9 +450,10 @@ void WebProcessPool::setOverrideLanguages(Vector&& languages) +@@ -455,9 +455,10 @@ void WebProcessPool::setOverrideLanguages(Vector&& languages) #endif #if USE(SOUP) for (Ref networkProcess : NetworkProcessProxy::allNetworkProcesses()) @@ -18434,7 +18134,7 @@ index b5a8f1b2da36d5c53d46d3b6e0a63e34d41db5d3..4df997597541f123cbd3f7e0b2016a26 void WebProcessPool::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled) { -@@ -926,7 +927,7 @@ void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDa +@@ -943,7 +944,7 @@ void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDa #endif parameters.cacheModel = LegacyGlobalSettings::singleton().cacheModel(); @@ -18444,10 +18144,10 @@ index b5a8f1b2da36d5c53d46d3b6e0a63e34d41db5d3..4df997597541f123cbd3f7e0b2016a26 parameters.urlSchemesRegisteredAsEmptyDocument = copyToVector(m_schemesToRegisterAsEmptyDocument); diff --git a/Source/WebKit/UIProcess/WebProcessProxy.cpp b/Source/WebKit/UIProcess/WebProcessProxy.cpp -index a508a91e3659c59614314d0f8abf559cf36818d2..866887ee5dfd6bacc12ab2068411270daae0d43e 100644 +index 31270a744c84c7e818bf42637658cd98db30f2b9..9e26b56dc40aeedc4afbb6cbe7b01f4cbcb32d0b 100644 --- a/Source/WebKit/UIProcess/WebProcessProxy.cpp +++ b/Source/WebKit/UIProcess/WebProcessProxy.cpp -@@ -190,6 +190,11 @@ Vector> WebProcessProxy::allProcesses() +@@ -194,6 +194,11 @@ Vector> WebProcessProxy::allProcesses() }); } @@ -18459,7 +18159,7 @@ index a508a91e3659c59614314d0f8abf559cf36818d2..866887ee5dfd6bacc12ab2068411270d RefPtr WebProcessProxy::processForIdentifier(ProcessIdentifier identifier) { return allProcessMap().get(identifier); -@@ -548,6 +553,26 @@ void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOpt +@@ -561,6 +566,26 @@ void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOpt if (WebKit::isInspectorProcessPool(protectedProcessPool())) launchOptions.extraInitializationData.add("inspector-process"_s, "1"_s); @@ -18487,10 +18187,10 @@ index a508a91e3659c59614314d0f8abf559cf36818d2..866887ee5dfd6bacc12ab2068411270d if (isPrewarmed()) diff --git a/Source/WebKit/UIProcess/WebProcessProxy.h b/Source/WebKit/UIProcess/WebProcessProxy.h -index 1b3c5b61e3e3a175632f2a92ca6947b05f05defc..38011071cef8dc662c617a18b16777956bad3868 100644 +index ac12422e6b49f1c3b935e0c05ea569522d1a4206..555bd49e0fb59fd6fdc2cfd32dc7614a096b924f 100644 --- a/Source/WebKit/UIProcess/WebProcessProxy.h +++ b/Source/WebKit/UIProcess/WebProcessProxy.h -@@ -170,6 +170,7 @@ public: +@@ -180,6 +180,7 @@ public: static void forWebPagesWithOrigin(PAL::SessionID, const WebCore::SecurityOriginData&, const Function&); static Vector> allowedFirstPartiesForCookies(); @@ -18498,23 +18198,11 @@ index 1b3c5b61e3e3a175632f2a92ca6947b05f05defc..38011071cef8dc662c617a18b1677795 void initializeWebProcess(WebProcessCreationParameters&&); -diff --git a/Source/WebKit/UIProcess/WebScreenOrientationManagerProxy.h b/Source/WebKit/UIProcess/WebScreenOrientationManagerProxy.h -index ed7f2f625f8dad92c3cfc8f5eff8a8acee9d1b1d..5aac771624649e0d9ccb4e52754dfac1d6228c71 100644 ---- a/Source/WebKit/UIProcess/WebScreenOrientationManagerProxy.h -+++ b/Source/WebKit/UIProcess/WebScreenOrientationManagerProxy.h -@@ -26,6 +26,7 @@ - #pragma once - - #include "MessageReceiver.h" -+#include "SharedPreferencesForWebProcess.h" - #include - #include - #include diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp -index a4a20ceb0dec282cebb7bf7d5f901c8ab8acfe0f..1780fd157b48474a63b5a6a5a583f57b64789ff0 100644 +index 09058b732dd75484320bca2c939f139e5057c845..aa9ea426f635d768cd2c901cccda72e0bbd165c8 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp -@@ -311,7 +311,8 @@ SOAuthorizationCoordinator& WebsiteDataStore::soAuthorizationCoordinator(const W +@@ -314,7 +314,8 @@ SOAuthorizationCoordinator& WebsiteDataStore::soAuthorizationCoordinator(const W static Ref networkProcessForSession(PAL::SessionID sessionID) { @@ -18524,7 +18212,7 @@ index a4a20ceb0dec282cebb7bf7d5f901c8ab8acfe0f..1780fd157b48474a63b5a6a5a583f57b if (sessionID.isEphemeral()) { // Reuse a previous persistent session network process for ephemeral sessions. for (auto& dataStore : allDataStores().values()) { -@@ -2324,6 +2325,12 @@ void WebsiteDataStore::originDirectoryForTesting(WebCore::ClientOrigin&& origin, +@@ -2354,6 +2355,12 @@ void WebsiteDataStore::originDirectoryForTesting(WebCore::ClientOrigin&& origin, protectedNetworkProcess()->websiteDataOriginDirectoryForTesting(m_sessionID, WTFMove(origin), type, WTFMove(completionHandler)); } @@ -18538,10 +18226,10 @@ index a4a20ceb0dec282cebb7bf7d5f901c8ab8acfe0f..1780fd157b48474a63b5a6a5a583f57b void WebsiteDataStore::hasAppBoundSession(CompletionHandler&& completionHandler) const { diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h -index fa85e9ad259588bb309c98c9550d4e46a487cbf1..092417a3e98eeddeea29b3d9b1c0131bac503386 100644 +index 903223f1276b9e5440ce66ba941255272209203f..c0b9b92f361cdca7bcfd3a8eb554c3bb015aac45 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h -@@ -97,6 +97,7 @@ class DeviceIdHashSaltStorage; +@@ -101,6 +101,7 @@ class DeviceIdHashSaltStorage; class DownloadProxy; class NetworkProcessProxy; class SOAuthorizationCoordinator; @@ -18549,7 +18237,7 @@ index fa85e9ad259588bb309c98c9550d4e46a487cbf1..092417a3e98eeddeea29b3d9b1c0131b class VirtualAuthenticatorManager; class WebPageProxy; class WebProcessPool; -@@ -112,12 +113,21 @@ enum class UnifiedOriginStorageLevel : uint8_t; +@@ -116,12 +117,21 @@ enum class UnifiedOriginStorageLevel : uint8_t; enum class WebsiteDataFetchOption : uint8_t; enum class WebsiteDataType : uint32_t; @@ -18571,7 +18259,7 @@ index fa85e9ad259588bb309c98c9550d4e46a487cbf1..092417a3e98eeddeea29b3d9b1c0131b class WebsiteDataStore : public API::ObjectImpl, public CanMakeWeakPtr { public: static Ref defaultDataStore(); -@@ -305,11 +315,13 @@ public: +@@ -310,11 +320,13 @@ public: const WebCore::CurlProxySettings& networkProxySettings() const { return m_proxySettings; } #endif @@ -18586,7 +18274,7 @@ index fa85e9ad259588bb309c98c9550d4e46a487cbf1..092417a3e98eeddeea29b3d9b1c0131b void setNetworkProxySettings(WebCore::SoupNetworkProxySettings&&); const WebCore::SoupNetworkProxySettings& networkProxySettings() const { return m_networkProxySettings; } void setCookiePersistentStorage(const String&, SoupCookiePersistentStorageType); -@@ -396,6 +408,12 @@ public: +@@ -404,6 +416,12 @@ public: static const String& defaultBaseDataDirectory(); #endif @@ -18599,7 +18287,7 @@ index fa85e9ad259588bb309c98c9550d4e46a487cbf1..092417a3e98eeddeea29b3d9b1c0131b void resetQuota(CompletionHandler&&); void resetStoragePersistedState(CompletionHandler&&); #if PLATFORM(IOS_FAMILY) -@@ -570,9 +588,11 @@ private: +@@ -589,9 +607,11 @@ private: WebCore::CurlProxySettings m_proxySettings; #endif @@ -18612,7 +18300,7 @@ index fa85e9ad259588bb309c98c9550d4e46a487cbf1..092417a3e98eeddeea29b3d9b1c0131b WebCore::SoupNetworkProxySettings m_networkProxySettings; String m_cookiePersistentStoragePath; SoupCookiePersistentStorageType m_cookiePersistentStorageType { SoupCookiePersistentStorageType::SQLite }; -@@ -599,6 +619,10 @@ private: +@@ -618,6 +638,10 @@ private: RefPtr m_cookieStore; RefPtr m_networkProcess; @@ -18624,10 +18312,10 @@ index fa85e9ad259588bb309c98c9550d4e46a487cbf1..092417a3e98eeddeea29b3d9b1c0131b std::unique_ptr m_soAuthorizationCoordinator; #endif diff --git a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp -index 351268d32fc4f25fe63021d1e6de62d0f2784ddb..0b8b0830a516085f0666dd04fa6be3c3dbde2e7c 100644 +index ac64c2a3cb5d1e8e46ba1835623a5c12825e3ea1..6ad7a5adc5198ae035c5cb815b6db8f033910f3a 100644 --- a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp +++ b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp -@@ -105,6 +105,14 @@ void GeoclueGeolocationProvider::stop() +@@ -114,6 +114,14 @@ void GeoclueGeolocationProvider::stop() } m_sourceType = LocationProviderSource::Unknown; @@ -18642,7 +18330,7 @@ index 351268d32fc4f25fe63021d1e6de62d0f2784ddb..0b8b0830a516085f0666dd04fa6be3c3 } void GeoclueGeolocationProvider::setEnableHighAccuracy(bool enabled) -@@ -377,6 +385,8 @@ void GeoclueGeolocationProvider::createGeoclueClient(const char* clientPath) +@@ -386,6 +394,8 @@ void GeoclueGeolocationProvider::createGeoclueClient(const char* clientPath) return; } @@ -18874,7 +18562,7 @@ index 0000000000000000000000000000000000000000..ac01ad1653b22a0f22c45a196659e68f +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.h b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.h new file mode 100644 -index 0000000000000000000000000000000000000000..394f07e1754be52b7d503d5720cba5d3724c5f4d +index 0000000000000000000000000000000000000000..441442d899e4088f5c24ae9f70c3e4ffa1e6d340 --- /dev/null +++ b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.h @@ -0,0 +1,61 @@ @@ -18932,7 +18620,7 @@ index 0000000000000000000000000000000000000000..394f07e1754be52b7d503d5720cba5d3 +private: + WebKitWebContext* findContext(WTF::String& error, PAL::SessionID); + -+ HashMap> m_idToContext; ++ UncheckedKeyHashMap> m_idToContext; + WebCore::SoupNetworkProxySettings m_proxySettings; +}; + @@ -18940,18 +18628,18 @@ index 0000000000000000000000000000000000000000..394f07e1754be52b7d503d5720cba5d3 + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h -index ce120bac5e1c6018ec637181d4b9d08cf85a1f32..2fe169f2f2976a73d275cc089d0df32541dbdec3 100644 +index 5529f52048b24290f424e877cd9dbfb890e02ffb..c2b76b6188dd9596c4a1f31c137daff7d7644c7f 100644 --- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h +++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h -@@ -30,6 +30,7 @@ - #include +@@ -32,6 +32,7 @@ + #include typedef struct _cairo cairo_t; +typedef struct _cairo_surface cairo_surface_t; #if USE(GTK4) typedef struct _GdkSnapshot GdkSnapshot; -@@ -59,6 +60,8 @@ public: +@@ -62,6 +63,8 @@ public: #else virtual bool paint(cairo_t*, const WebCore::IntRect&) = 0; #endif @@ -18961,11 +18649,11 @@ index ce120bac5e1c6018ec637181d4b9d08cf85a1f32..2fe169f2f2976a73d275cc089d0df325 virtual void unrealize() { }; virtual int renderHostFileDescriptor() { return -1; } diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp -index 95f8f8a3cc14be838e5170a94ec4b2328afde62f..0a4af599d5e711b9c4eaa1c27cd7442121e07627 100644 +index 92d972eeef867b680ef0266d24f47827fe0d64b5..afb1e4d9dfae59be15692635e5334a5078bfef95 100644 --- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp +++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp -@@ -707,4 +707,30 @@ RendererBufferFormat AcceleratedBackingStoreDMABuf::bufferFormat() const - return buffer ? buffer->format() : RendererBufferFormat { }; +@@ -811,4 +811,30 @@ RefPtr AcceleratedBackingStoreDMABuf::bufferAsNativeImageF + return m_committedBuffer->asNativeImageForTesting(); } +// Playwright begin @@ -18996,10 +18684,10 @@ index 95f8f8a3cc14be838e5170a94ec4b2328afde62f..0a4af599d5e711b9c4eaa1c27cd74421 + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.h b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.h -index 8fa631f95a39298a9b4876b7d1b52bcacc3dc4af..d8c15d27ad8210739da490f32999b395fae9b65b 100644 +index 87275e2c71e934f76c979e30375e78763a476814..5776d81c12e653404c1c637d4d7060e9123f12e5 100644 --- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.h +++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.h -@@ -94,6 +94,7 @@ private: +@@ -98,6 +98,7 @@ private: #else bool paint(cairo_t*, const WebCore::IntRect&) override; #endif @@ -19007,7 +18695,7 @@ index 8fa631f95a39298a9b4876b7d1b52bcacc3dc4af..d8c15d27ad8210739da490f32999b395 void unrealize() override; void update(const LayerTreeContext&) override; RendererBufferFormat bufferFormat() const override; -@@ -242,6 +243,9 @@ private: +@@ -253,6 +254,9 @@ private: RefPtr m_committedBuffer; WebCore::Region m_pendingDamageRegion; HashMap> m_buffers; @@ -19071,19 +18759,19 @@ index 0000000000000000000000000000000000000000..bf78de1915940c2d3292514cf0fe4e68 +} + +} // namespace WebKit -diff --git a/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.cpp b/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.cpp -index 97191083e1c5b5283599e394e56553fc5e5cd6a1..e8c7cbb6cd9431b1720aafb8dfd0abdc97f17a39 100644 ---- a/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.cpp -+++ b/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.cpp -@@ -35,6 +35,8 @@ - #include - #include - -+using namespace WebCore; -+ - namespace WebKit { +diff --git a/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp +index aa702b018d881739fb464246e7c7d7236adfe97b..f711e1608e6d8b988d2d0bc99893d5b0137a07ae 100644 +--- a/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp ++++ b/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp +@@ -117,6 +117,8 @@ int SystemSettingsManagerProxy::xftDPI() const - Ref WebDateTimePickerGtk::create(WebPageProxy& page) + bool SystemSettingsManagerProxy::followFontSystemSettings() const + { ++ // Align with WPE's behavior, which always returns false. ++ return false; + #if USE(GTK4) + #if GTK_CHECK_VERSION(4, 16, 0) + GtkFontRendering fontRendering; diff --git a/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d9672b0f831b5b7f6acf14ede26e1e8e9a65389 @@ -19306,19 +18994,6 @@ index 2a17b59c9be6ecc76b0ec0a16d9f4866dffa0bf4..0d5c58a88b0e5197254d0eb5bd6eee04 m_primarySelectionOwner = frame; } -diff --git a/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm b/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm -index fa78d12c9cbc8c3d0d3957afb98536d2a411e241..f13c49a59ba14eec2f1d345f2837f47dd62bc049 100644 ---- a/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm -+++ b/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm -@@ -495,6 +495,8 @@ IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect) - - void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool eventWasHandled) - { -+ if (!event.nativeEvent()) -+ return; - [contentView() _didHandleKeyEvent:event.nativeEvent() eventWasHandled:eventWasHandled]; - } - diff --git a/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h new file mode 100644 index 0000000000000000000000000000000000000000..2aabc02a4b5432f68a6e85fd9689775608f05a67 @@ -19529,10 +19204,10 @@ index 0000000000000000000000000000000000000000..8adbd51bfecad2a273117588bf50f8f7 + +#endif diff --git a/Source/WebKit/UIProcess/mac/PageClientImplMac.h b/Source/WebKit/UIProcess/mac/PageClientImplMac.h -index 48c64d82d9cb1274d4127b5b719a5a80d711c54c..5f27aafbb74af7b42aa7096b25e388bce43dec24 100644 +index c8ec967cdc8b32e7b9349460794c35b2c6b45d7f..a8ccc70d9f0defd9ac4e8c8f45064bc3b2b4bfac 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.h +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.h -@@ -58,6 +58,8 @@ class PageClientImpl final : public PageClientImplCocoa +@@ -60,6 +60,8 @@ class PageClientImpl final : public PageClientImplCocoa WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(PageClientImpl); #endif public: @@ -19541,7 +19216,7 @@ index 48c64d82d9cb1274d4127b5b719a5a80d711c54c..5f27aafbb74af7b42aa7096b25e388bc PageClientImpl(NSView *, WKWebView *); virtual ~PageClientImpl(); -@@ -174,6 +176,9 @@ private: +@@ -175,6 +177,9 @@ private: void updateAcceleratedCompositingMode(const LayerTreeContext&) override; void didFirstLayerFlush(const LayerTreeContext&) override; @@ -19551,7 +19226,7 @@ index 48c64d82d9cb1274d4127b5b719a5a80d711c54c..5f27aafbb74af7b42aa7096b25e388bc RefPtr takeViewSnapshot(std::optional&&) override; RefPtr takeViewSnapshot(std::optional&&, ForceSoftwareCapturingViewportSnapshot) override; void wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent&) override; -@@ -229,6 +234,10 @@ private: +@@ -230,6 +235,10 @@ private: void beganExitFullScreen(const WebCore::IntRect& initialFrame, const WebCore::IntRect& finalFrame) override; #endif @@ -19563,7 +19238,7 @@ index 48c64d82d9cb1274d4127b5b719a5a80d711c54c..5f27aafbb74af7b42aa7096b25e388bc void navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem&) override; void navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem&) override; diff --git a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm -index 8af5332c0d74f1b6e057c142f830cfae4274c81a..e452dfa8ba0bf97770f091f1f69d6dc01ac03358 100644 +index dba9aae7c29f59127a80461aedc8ac10cc1cef66..addadd854c4fa5c999eb1ae865c8e31d2e37b03f 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm @@ -110,6 +110,13 @@ namespace WebKit { @@ -19620,7 +19295,7 @@ index 8af5332c0d74f1b6e057c142f830cfae4274c81a..e452dfa8ba0bf97770f091f1f69d6dc0 } void PageClientImpl::toolTipChanged(const String& oldToolTip, const String& newToolTip) -@@ -482,6 +499,8 @@ IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect) +@@ -478,6 +495,8 @@ IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect) void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool eventWasHandled) { @@ -19629,7 +19304,7 @@ index 8af5332c0d74f1b6e057c142f830cfae4274c81a..e452dfa8ba0bf97770f091f1f69d6dc0 m_impl->doneWithKeyEvent(event.nativeEvent(), eventWasHandled); } -@@ -501,6 +520,8 @@ void PageClientImpl::computeHasVisualSearchResults(const URL& imageURL, Shareabl +@@ -497,6 +516,8 @@ void PageClientImpl::computeHasVisualSearchResults(const URL& imageURL, Shareabl RefPtr PageClientImpl::createPopupMenuProxy(WebPageProxy& page) { @@ -19638,7 +19313,7 @@ index 8af5332c0d74f1b6e057c142f830cfae4274c81a..e452dfa8ba0bf97770f091f1f69d6dc0 return WebPopupMenuProxyMac::create(m_view, page.popupMenuClient()); } -@@ -642,6 +663,12 @@ CALayer *PageClientImpl::footerBannerLayer() const +@@ -638,6 +659,12 @@ CALayer *PageClientImpl::footerBannerLayer() const return m_impl->footerBannerLayer(); } @@ -19651,7 +19326,7 @@ index 8af5332c0d74f1b6e057c142f830cfae4274c81a..e452dfa8ba0bf97770f091f1f69d6dc0 RefPtr PageClientImpl::takeViewSnapshot(std::optional&&) { return m_impl->takeViewSnapshot(); -@@ -837,6 +864,13 @@ void PageClientImpl::beganExitFullScreen(const IntRect& initialFrame, const IntR +@@ -833,6 +860,13 @@ void PageClientImpl::beganExitFullScreen(const IntRect& initialFrame, const IntR #endif // ENABLE(FULLSCREEN_API) @@ -19665,7 +19340,7 @@ index 8af5332c0d74f1b6e057c142f830cfae4274c81a..e452dfa8ba0bf97770f091f1f69d6dc0 void PageClientImpl::navigationGestureDidBegin() { m_impl->dismissContentRelativeChildWindowsWithAnimation(true); -@@ -1020,6 +1054,9 @@ void PageClientImpl::requestScrollToRect(const WebCore::FloatRect& targetRect, c +@@ -1011,6 +1045,9 @@ void PageClientImpl::requestScrollToRect(const WebCore::FloatRect& targetRect, c bool PageClientImpl::windowIsFrontWindowUnderMouse(const NativeWebMouseEvent& event) { @@ -19676,15 +19351,16 @@ index 8af5332c0d74f1b6e057c142f830cfae4274c81a..e452dfa8ba0bf97770f091f1f69d6dc0 } diff --git a/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in b/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in -index 21c925bafb662dbe961baaad7f25bf4296236d76..5496a33c558a00a5ba96d10223e600aa38de99c4 100644 +index e0a61ae15b79e32701b2f4a2a6de6c105fb39446..1792da3491e88ee76a501f271938592de19f7ae4 100644 --- a/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in +++ b/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in -@@ -20,11 +20,11 @@ +@@ -20,12 +20,12 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#if ENABLE(SEC_ITEM_SHIM) - messages -> SecItemShimProxy NotRefCounted { + [ExceptionForEnabledBy] + messages -> SecItemShimProxy { -#if ENABLE(SEC_ITEM_SHIM) SecItemRequestSync(WebKit::SecItemRequestData request) -> (std::optional response) Synchronous @@ -19694,10 +19370,10 @@ index 21c925bafb662dbe961baaad7f25bf4296236d76..5496a33c558a00a5ba96d10223e600aa } +#endif diff --git a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h -index e34faa8ae2933154efdbf0492a2f17af7a46f83b..54b509837bb767ac3ab28d1d7059462ca7a1170b 100644 +index b668c229f2e8bd077b19a8a6344416098895f8a0..e9b67c72cfc91fec86887941a760f6899696624f 100644 --- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h +++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h -@@ -78,6 +78,7 @@ private: +@@ -80,6 +80,7 @@ private: void show() override; void showContextMenuWithItems(Vector>&&) override; void useContextMenuItems(Vector>&&) override; @@ -19706,10 +19382,10 @@ index e34faa8ae2933154efdbf0492a2f17af7a46f83b..54b509837bb767ac3ab28d1d7059462c bool showAfterPostProcessingContextData(); diff --git a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm -index fa0104e2bf2d81e0c1d9a4f4765033dd84cc94db..a073c9203099f024dad99156582a20996065d019 100644 +index 4abfcf22cbdce49e3e15993b07700866fa8e97f9..2a90b5d222ccdec8725c64f3102bebd870360fa9 100644 --- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm +++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm -@@ -504,6 +504,12 @@ void WebContextMenuProxyMac::getShareMenuItem(CompletionHandler WebContextMenuProxyMac::createShareMenuItem(ShareMenuItemT } #endif @@ -19914,10 +19590,10 @@ index 0000000000000000000000000000000000000000..dd52991f936aa1c046b404801ee97237 + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/mac/WebViewImpl.h b/Source/WebKit/UIProcess/mac/WebViewImpl.h -index 6f9f2473b1722fb9f12e1f442aabc799181bd01e..d6f1e0984db6e8238d4bc66b04235d3bd20921ac 100644 +index f519288e2a405f48d9224599eb678c919ff77af1..cc151e7b828536e9509bcb5fa23d19b4f2efc10f 100644 --- a/Source/WebKit/UIProcess/mac/WebViewImpl.h +++ b/Source/WebKit/UIProcess/mac/WebViewImpl.h -@@ -538,6 +538,9 @@ public: +@@ -543,6 +543,9 @@ public: void provideDataForPasteboard(NSPasteboard *, NSString *type); NSArray *namesOfPromisedFilesDroppedAtDestination(NSURL *dropDestination); @@ -19928,10 +19604,10 @@ index 6f9f2473b1722fb9f12e1f442aabc799181bd01e..d6f1e0984db6e8238d4bc66b04235d3b RefPtr takeViewSnapshot(ForceSoftwareCapturingViewportSnapshot); void saveBackForwardSnapshotForCurrentItem(); diff --git a/Source/WebKit/UIProcess/mac/WebViewImpl.mm b/Source/WebKit/UIProcess/mac/WebViewImpl.mm -index 5775c9c17409f13c967b0fdb2030e4bb65982c50..35f3e6bcd38f93066c5d54e906431ae1ba23fa9f 100644 +index 032961f58ab7990c8b353c0fcc849e8d03c145ac..04866658cbfbcf8dad31e51f94d0419a1466e62a 100644 --- a/Source/WebKit/UIProcess/mac/WebViewImpl.mm +++ b/Source/WebKit/UIProcess/mac/WebViewImpl.mm -@@ -2416,6 +2416,11 @@ WebCore::DestinationColorSpace WebViewImpl::colorSpace() +@@ -2390,6 +2390,11 @@ WebCore::DestinationColorSpace WebViewImpl::colorSpace() if (!m_colorSpace) m_colorSpace = [NSColorSpace sRGBColorSpace]; } @@ -19943,8 +19619,8 @@ index 5775c9c17409f13c967b0fdb2030e4bb65982c50..35f3e6bcd38f93066c5d54e906431ae1 ASSERT(m_colorSpace); return WebCore::DestinationColorSpace { [m_colorSpace CGColorSpace] }; -@@ -4554,6 +4559,17 @@ static RetainPtr takeWindowSnapshot(CGSWindowID windowID, bool captu - return adoptCF(WebCore::cgWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, imageOptions)); +@@ -4528,6 +4533,17 @@ static RetainPtr takeWindowSnapshot(CGSWindowID windowID, bool captu + return WebCore::cgWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, imageOptions); } +// Paywright begin @@ -19963,10 +19639,10 @@ index 5775c9c17409f13c967b0fdb2030e4bb65982c50..35f3e6bcd38f93066c5d54e906431ae1 return takeViewSnapshot(ForceSoftwareCapturingViewportSnapshot::No); diff --git a/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..dd7fe0604188bb025f361f1c44685e38bbf935ca +index 0000000000000000000000000000000000000000..4f54a9445e5a7ecdb750c5c521da4f397776e633 --- /dev/null +++ b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp -@@ -0,0 +1,90 @@ +@@ -0,0 +1,89 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * @@ -20046,7 +19722,6 @@ index 0000000000000000000000000000000000000000..dd7fe0604188bb025f361f1c44685e38 + WebCore::CurlProxySettings settings(WTFMove(proxyURL), String(proxyBypassList)); + browserContext->dataStore->setNetworkProxySettings(WTFMove(settings)); + } -+ PAL::SessionID sessionID = browserContext->dataStore->sessionID(); + return browserContext; +} + @@ -20319,7 +19994,7 @@ index 0000000000000000000000000000000000000000..8b474c730139b44a13c9d5b2d13ee204 + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/win/WebView.cpp b/Source/WebKit/UIProcess/win/WebView.cpp -index 2946296119ea0f551f02d37c41a8e5cec5b74249..68501ee0817ce21f48300a74f05726882630b23c 100644 +index 8b521de62266d4a7fad3624b548401a4c8056f9f..c6da98e334fbd090a8c63b690afb25697ac344d7 100644 --- a/Source/WebKit/UIProcess/win/WebView.cpp +++ b/Source/WebKit/UIProcess/win/WebView.cpp @@ -556,9 +556,8 @@ LRESULT WebView::onSizeEvent(HWND hwnd, UINT, WPARAM, LPARAM lParam, bool& handl @@ -20736,18 +20411,6 @@ index 0000000000000000000000000000000000000000..a7d88f8c745f95af21db71dcfce368ba +} + +} // namespace WebKit -diff --git a/Source/WebKit/UIProcess/wpe/WebPageProxyWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPageProxyWPE.cpp -index 33c5c1918e7496f08166a168e9ba6b091515e547..bdc4976cb290ff608c6bcae37a2ec2addd59b221 100644 ---- a/Source/WebKit/UIProcess/wpe/WebPageProxyWPE.cpp -+++ b/Source/WebKit/UIProcess/wpe/WebPageProxyWPE.cpp -@@ -31,6 +31,7 @@ - #include "PageClientImpl.h" - #include "UserMessage.h" - #include "WebProcessProxy.h" -+#include - #include - - #if USE(ATK) diff --git a/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp index 9b688ad328317fea4fd96ce66e9714bad8f0f937..402a36a9c565e13ec298aa7f014f0d9208ebddb7 100644 --- a/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp @@ -20763,23 +20426,24 @@ index 9b688ad328317fea4fd96ce66e9714bad8f0f937..402a36a9c565e13ec298aa7f014f0d92 } } // namespace WebKit -diff --git a/Source/WebKit/WPEPlatform/CMakeLists.txt b/Source/WebKit/WPEPlatform/CMakeLists.txt -index 2b64d1b5b013d53b18b7757fe3b3f3d9a0501571..e8f28808f5ef0532319a4462fd285c0770d7ce52 100644 ---- a/Source/WebKit/WPEPlatform/CMakeLists.txt -+++ b/Source/WebKit/WPEPlatform/CMakeLists.txt -@@ -96,6 +96,7 @@ set(WPEPlatform_SYSTEM_INCLUDE_DIRECTORIES - - set(WPEPlatform_LIBRARIES - Epoxy::Epoxy -+ rt - WTF - ${GLIB_GIO_LIBRARIES} - ${GLIB_GOBJECT_LIBRARIES} +diff --git a/Source/WebKit/UnifiedSources-output.xcfilelist b/Source/WebKit/UnifiedSources-output.xcfilelist +index c103a90e720933a10b736194139973f16c33551a..d0985c9258b3e19701498f7cbf4d0add3c584b8c 100644 +--- a/Source/WebKit/UnifiedSources-output.xcfilelist ++++ b/Source/WebKit/UnifiedSources-output.xcfilelist +@@ -55,6 +55,8 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/unified-sources/UnifiedSource134.cpp + $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/unified-sources/UnifiedSource135.cpp + $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/unified-sources/UnifiedSource136.cpp + $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/unified-sources/UnifiedSource137.cpp ++$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/unified-sources/UnifiedSource138.cpp ++$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/unified-sources/UnifiedSource139.cpp + $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/unified-sources/UnifiedSource14-mm.mm + $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/unified-sources/UnifiedSource14.cpp + $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/unified-sources/UnifiedSource15-mm.mm diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj -index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e5171783467 100644 +index 02610cb75b88760c441c0532a97fb0cb2eb838c6..01b5efc4a8013bef8e6bad79a0bb277f06450ee9 100644 --- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj +++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj -@@ -1585,6 +1585,7 @@ +@@ -1527,6 +1527,7 @@ 5CABDC8722C40FED001EDE8E /* APIMessageListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CABDC8322C40FA7001EDE8E /* APIMessageListener.h */; }; 5CADDE05215046BD0067D309 /* WKWebProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C74300E21500492004BFA17 /* WKWebProcess.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5CAECB6627465AE400AB78D0 /* UnifiedSource115.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CAECB5E27465AE300AB78D0 /* UnifiedSource115.cpp */; }; @@ -20787,7 +20451,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 5CAF7AA726F93AB00003F19E /* adattributiond.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CAF7AA526F93A950003F19E /* adattributiond.cpp */; }; 5CAFDE452130846300B1F7E1 /* _WKInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CAFDE422130843500B1F7E1 /* _WKInspector.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5CAFDE472130846A00B1F7E1 /* _WKInspectorInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CAFDE442130843600B1F7E1 /* _WKInspectorInternal.h */; }; -@@ -2407,6 +2408,18 @@ +@@ -2301,6 +2302,18 @@ DF0C5F28252ECB8E00D921DB /* WKDownload.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F24252ECB8D00D921DB /* WKDownload.h */; settings = {ATTRIBUTES = (Public, ); }; }; DF0C5F2A252ECB8E00D921DB /* WKDownloadDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F26252ECB8E00D921DB /* WKDownloadDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; DF0C5F2B252ED44000D921DB /* WKDownloadInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F25252ECB8E00D921DB /* WKDownloadInternal.h */; }; @@ -20806,7 +20470,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 DF462E0F23F22F5500EFF35F /* WKHTTPCookieStorePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF462E0E23F22F5300EFF35F /* WKHTTPCookieStorePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; DF462E1223F338BE00EFF35F /* WKContentWorldPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF462E1123F338AD00EFF35F /* WKContentWorldPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; DF7A231C291B088D00B98DF3 /* WKSnapshotConfigurationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF7A231B291B088D00B98DF3 /* WKSnapshotConfigurationPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; -@@ -2500,6 +2513,8 @@ +@@ -2392,6 +2405,8 @@ E5BEF6822130C48000F31111 /* WebDataListSuggestionsDropdownIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = E5BEF6802130C47F00F31111 /* WebDataListSuggestionsDropdownIOS.h */; }; E5CB07DC20E1678F0022C183 /* WKFormColorControl.h in Headers */ = {isa = PBXBuildFile; fileRef = E5CB07DA20E1678F0022C183 /* WKFormColorControl.h */; }; E5CBA76427A318E100DF7858 /* UnifiedSource120.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA75F27A3187800DF7858 /* UnifiedSource120.cpp */; }; @@ -20815,7 +20479,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 E5CBA76527A318E100DF7858 /* UnifiedSource118.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76127A3187900DF7858 /* UnifiedSource118.cpp */; }; E5CBA76627A318E100DF7858 /* UnifiedSource116.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76327A3187B00DF7858 /* UnifiedSource116.cpp */; }; E5CBA76727A318E100DF7858 /* UnifiedSource119.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76027A3187900DF7858 /* UnifiedSource119.cpp */; }; -@@ -2523,6 +2538,9 @@ +@@ -2415,6 +2430,9 @@ EBA8D3B727A5E33F00CB7900 /* PushServiceConnection.mm in Sources */ = {isa = PBXBuildFile; fileRef = EBA8D3B127A5E33F00CB7900 /* PushServiceConnection.mm */; }; EBDF51D12C8FBC4700EA1376 /* WebsitePushAndNotificationsEnabledPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = EBDF51CF2C8FBC4700EA1376 /* WebsitePushAndNotificationsEnabledPolicy.h */; }; ED82A7F2128C6FAF004477B3 /* WKBundlePageOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A22F0FF1289FCD90085E74F /* WKBundlePageOverlay.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -20824,8 +20488,17 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 + F3867F0A24607D4E008F0F31 /* InspectorScreencastAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = F3867F0424607D2B008F0F31 /* InspectorScreencastAgent.h */; }; F409BA181E6E64BC009DA28E /* WKDragDestinationAction.h in Headers */ = {isa = PBXBuildFile; fileRef = F409BA171E6E64B3009DA28E /* WKDragDestinationAction.h */; settings = {ATTRIBUTES = (Private, ); }; }; F40C3B712AB401C5007A3567 /* WKDatePickerPopoverController.h in Headers */ = {isa = PBXBuildFile; fileRef = F40C3B6F2AB40167007A3567 /* WKDatePickerPopoverController.h */; }; - F416F1C02C5C3E360085D8DD /* WKScrollViewTrackingTapGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = F416F1BE2C5C3E360085D8DD /* WKScrollViewTrackingTapGestureRecognizer.h */; }; -@@ -6282,6 +6300,7 @@ + F41145682CD939E0004CDBD1 /* _WKTouchEventGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = F41145652CD939E0004CDBD1 /* _WKTouchEventGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; }; +@@ -2518,6 +2536,8 @@ + FAE61CE82D0A5608000D238D /* UnifiedSource136.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE61CE12D0A5606000D238D /* UnifiedSource136.cpp */; }; + FAE61CE92D0A5608000D238D /* UnifiedSource133.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE61CE22D0A5607000D238D /* UnifiedSource133.cpp */; }; + FAE61CEA2D0A5608000D238D /* UnifiedSource137.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE61CE32D0A5607000D238D /* UnifiedSource137.cpp */; }; ++ FAE61CED2D0A5608000D238D /* UnifiedSource138.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE61CE62D0A5607000D238D /* UnifiedSource138.cpp */; }; ++ FAE61CEE2D0A5608000D238D /* UnifiedSource139.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE61CE72D0A5607000D238D /* UnifiedSource139.cpp */; }; + FAE61CEB2D0A5608000D238D /* UnifiedSource135.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE61CE42D0A5607000D238D /* UnifiedSource135.cpp */; }; + FAE61CEC2D0A5608000D238D /* UnifiedSource131.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE61CE52D0A5607000D238D /* UnifiedSource131.cpp */; }; + FAF27D302D2851EB00F1F0BB /* CoreIPCPKSecureElementPass.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAF27D2F2D2850D400F1F0BB /* CoreIPCPKSecureElementPass.mm */; }; +@@ -6228,6 +6248,7 @@ 5CABDC8522C40FCC001EDE8E /* WKMessageListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKMessageListener.h; sourceTree = ""; }; 5CABE07A28F60E8A00D83FD9 /* WebPushMessage.serialization.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebPushMessage.serialization.in; sourceTree = ""; }; 5CADDE0D2151AA010067D309 /* AuthenticationChallengeDisposition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthenticationChallengeDisposition.h; sourceTree = ""; }; @@ -20833,7 +20506,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 5CAECB5E27465AE300AB78D0 /* UnifiedSource115.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource115.cpp; sourceTree = ""; }; 5CAF7AA426F93A750003F19E /* adattributiond */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = adattributiond; sourceTree = BUILT_PRODUCTS_DIR; }; 5CAF7AA526F93A950003F19E /* adattributiond.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = adattributiond.cpp; sourceTree = ""; }; -@@ -7969,6 +7988,19 @@ +@@ -7926,6 +7947,19 @@ DF0C5F24252ECB8D00D921DB /* WKDownload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownload.h; sourceTree = ""; }; DF0C5F25252ECB8E00D921DB /* WKDownloadInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownloadInternal.h; sourceTree = ""; }; DF0C5F26252ECB8E00D921DB /* WKDownloadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownloadDelegate.h; sourceTree = ""; }; @@ -20853,7 +20526,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 DF462E0E23F22F5300EFF35F /* WKHTTPCookieStorePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKHTTPCookieStorePrivate.h; sourceTree = ""; }; DF462E1123F338AD00EFF35F /* WKContentWorldPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKContentWorldPrivate.h; sourceTree = ""; }; DF58C6311371AC5800F9A37C /* NativeWebWheelEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeWebWheelEvent.h; sourceTree = ""; }; -@@ -8129,6 +8161,8 @@ +@@ -8091,6 +8125,8 @@ E5CBA76127A3187900DF7858 /* UnifiedSource118.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource118.cpp; sourceTree = ""; }; E5CBA76227A3187900DF7858 /* UnifiedSource117.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource117.cpp; sourceTree = ""; }; E5CBA76327A3187B00DF7858 /* UnifiedSource116.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource116.cpp; sourceTree = ""; }; @@ -20862,7 +20535,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 E5DEFA6726F8F42600AB68DB /* PhotosUISPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PhotosUISPI.h; sourceTree = ""; }; EB0D312D275AE13300863D8F /* com.apple.webkit.webpushd.mac.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.webkit.webpushd.mac.plist; sourceTree = ""; }; EB0D312E275AE13300863D8F /* com.apple.webkit.webpushd.ios.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.webkit.webpushd.ios.plist; sourceTree = ""; }; -@@ -8162,6 +8196,14 @@ +@@ -8124,6 +8160,14 @@ ECA680D31E6904B500731D20 /* ExtraPrivateSymbolsForTAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExtraPrivateSymbolsForTAPI.h; sourceTree = ""; }; ECBFC1DB1E6A4D66000300C7 /* ExtraPublicSymbolsForTAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExtraPublicSymbolsForTAPI.h; sourceTree = ""; }; F036978715F4BF0500C3A80E /* WebColorPicker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebColorPicker.cpp; sourceTree = ""; }; @@ -20877,7 +20550,16 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 F409BA171E6E64B3009DA28E /* WKDragDestinationAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDragDestinationAction.h; sourceTree = ""; }; F40C3B6F2AB40167007A3567 /* WKDatePickerPopoverController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WKDatePickerPopoverController.h; path = ios/forms/WKDatePickerPopoverController.h; sourceTree = ""; }; F40C3B702AB40167007A3567 /* WKDatePickerPopoverController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = WKDatePickerPopoverController.mm; path = ios/forms/WKDatePickerPopoverController.mm; sourceTree = ""; }; -@@ -8487,6 +8529,7 @@ +@@ -8351,6 +8395,8 @@ + FAE61CE32D0A5607000D238D /* UnifiedSource137.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource137.cpp; sourceTree = ""; }; + FAE61CE42D0A5607000D238D /* UnifiedSource135.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource135.cpp; sourceTree = ""; }; + FAE61CE52D0A5607000D238D /* UnifiedSource131.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource131.cpp; sourceTree = ""; }; ++ FAE61CE62D0A5607000D238D /* UnifiedSource138.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnifiedSource138.cpp; sourceTree = ""; }; ++ FAE61CE72D0A5607000D238D /* UnifiedSource139.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnifiedSource139.cpp; sourceTree = ""; }; + FAF27D2E2D2850D400F1F0BB /* CoreIPCPKSecureElementPass.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CoreIPCPKSecureElementPass.h; sourceTree = ""; }; + FAF27D2F2D2850D400F1F0BB /* CoreIPCPKSecureElementPass.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreIPCPKSecureElementPass.mm; sourceTree = ""; }; + FED3C1DA1B447AE800E0EB7F /* APISerializedScriptValueCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = APISerializedScriptValueCocoa.mm; sourceTree = ""; }; +@@ -8467,6 +8513,7 @@ 3766F9EE189A1241003CF19B /* JavaScriptCore.framework in Frameworks */, 3766F9F1189A1254003CF19B /* libicucore.dylib in Frameworks */, 7B9FC5BB28A5233B007570E7 /* libWebKitPlatform.a in Frameworks */, @@ -20885,7 +20567,16 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 3766F9EF189A1244003CF19B /* QuartzCore.framework in Frameworks */, 37694525184FC6B600CDE21F /* Security.framework in Frameworks */, 37BEC4DD1948FC6A008B4286 /* WebCore.framework in Frameworks */, -@@ -11435,6 +11478,7 @@ +@@ -11055,6 +11102,8 @@ + FAE61CE42D0A5607000D238D /* UnifiedSource135.cpp */, + FAE61CE12D0A5606000D238D /* UnifiedSource136.cpp */, + FAE61CE32D0A5607000D238D /* UnifiedSource137.cpp */, ++ FAE61CE62D0A5607000D238D /* UnifiedSource138.cpp */, ++ FAE61CE72D0A5607000D238D /* UnifiedSource139.cpp */, + ); + path = "unified-sources"; + sourceTree = ""; +@@ -11516,6 +11565,7 @@ 99788ACA1F421DCA00C08000 /* _WKAutomationSessionConfiguration.mm */, 990D28A81C6404B000986977 /* _WKAutomationSessionDelegate.h */, 990D28AF1C65203900986977 /* _WKAutomationSessionInternal.h */, @@ -20893,7 +20584,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 5C4609E222430E4C009943C2 /* _WKContentRuleListAction.h */, 5C4609E322430E4D009943C2 /* _WKContentRuleListAction.mm */, 5C4609E422430E4D009943C2 /* _WKContentRuleListActionInternal.h */, -@@ -12785,6 +12829,7 @@ +@@ -12864,6 +12914,7 @@ E34B110C27C46BC6006D2F2E /* libWebCoreTestShim.dylib */, E34B110F27C46D09006D2F2E /* libWebCoreTestSupport.dylib */, DDE992F4278D06D900F60D26 /* libWebKitAdditions.a */, @@ -20901,7 +20592,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 57A9FF15252C6AEF006A2040 /* libWTF.a */, 5750F32A2032D4E500389347 /* LocalAuthentication.framework */, 570DAAB0230273D200E8FC04 /* NearField.framework */, -@@ -13359,6 +13404,12 @@ +@@ -13437,6 +13488,12 @@ children = ( 9197940423DBC4BB00257892 /* InspectorBrowserAgent.cpp */, 9197940323DBC4BB00257892 /* InspectorBrowserAgent.h */, @@ -20914,7 +20605,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 ); path = Agents; sourceTree = ""; -@@ -13367,6 +13418,7 @@ +@@ -13445,6 +13502,7 @@ isa = PBXGroup; children = ( A5D3504D1D78F0D2005124A9 /* RemoteWebInspectorUIProxyMac.mm */, @@ -20922,7 +20613,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 1CA8B935127C774E00576C2B /* WebInspectorUIProxyMac.mm */, 99A7ACE326012919006D57FD /* WKInspectorResourceURLSchemeHandler.h */, 99A7ACE42601291A006D57FD /* WKInspectorResourceURLSchemeHandler.mm */, -@@ -14074,6 +14126,7 @@ +@@ -14162,6 +14220,7 @@ E1513C65166EABB200149FCB /* AuxiliaryProcessProxy.h */, 46A2B6061E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.cpp */, 46A2B6071E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.h */, @@ -20930,7 +20621,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 5C6D69352AC3935D0099BDAF /* BrowsingContextGroup.cpp */, 5C6D69362AC3935D0099BDAF /* BrowsingContextGroup.h */, 5CA98549210BEB5A0057EB6B /* BrowsingWarning.h */, -@@ -14098,6 +14151,8 @@ +@@ -14186,6 +14245,8 @@ BC06F43912DBCCFB002D78DE /* GeolocationPermissionRequestProxy.cpp */, BC06F43812DBCCFB002D78DE /* GeolocationPermissionRequestProxy.h */, 2DD5A72A1EBF09A7009BA597 /* HiddenPageThrottlingAutoIncreasesCounter.h */, @@ -20939,7 +20630,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 5CEABA2B2333251400797797 /* LegacyGlobalSettings.cpp */, 5CEABA2A2333247700797797 /* LegacyGlobalSettings.h */, 31607F3819627002009B87DA /* LegacySessionStateCoding.h */, -@@ -14131,6 +14186,7 @@ +@@ -14219,6 +14280,7 @@ 1A0C227D2451130A00ED614D /* QuickLookThumbnailingSoftLink.mm */, 1AEE57232409F142002005D6 /* QuickLookThumbnailLoader.h */, 1AEE57242409F142002005D6 /* QuickLookThumbnailLoader.mm */, @@ -20947,7 +20638,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 5CCB54DC2A4FEA6A0005FAA8 /* RemotePageDrawingAreaProxy.cpp */, 5CCB54DB2A4FEA6A0005FAA8 /* RemotePageDrawingAreaProxy.h */, 5C907E9A294D507100B3402D /* RemotePageProxy.cpp */, -@@ -14231,6 +14287,8 @@ +@@ -14319,6 +14381,8 @@ BC7B6204129A0A6700D174A4 /* WebPageGroup.h */, 2D9EA3101A96D9EB002D2807 /* WebPageInjectedBundleClient.cpp */, 2D9EA30E1A96CBFF002D2807 /* WebPageInjectedBundleClient.h */, @@ -20956,7 +20647,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 9B7F8A502C785725000057F3 /* WebPageLoadTiming.h */, BC111B0B112F5E4F00337BAB /* WebPageProxy.cpp */, BC032DCB10F4389F0058C15A /* WebPageProxy.h */, -@@ -14406,6 +14464,7 @@ +@@ -14497,6 +14561,7 @@ BC646C1911DD399F006455B0 /* WKBackForwardListItemRef.h */, BC646C1611DD399F006455B0 /* WKBackForwardListRef.cpp */, BC646C1711DD399F006455B0 /* WKBackForwardListRef.h */, @@ -20964,7 +20655,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 BCB9E24A1120E15C00A137E0 /* WKContext.cpp */, BCB9E2491120E15C00A137E0 /* WKContext.h */, 1AE52F9319201F6B00A1FA37 /* WKContextConfigurationRef.cpp */, -@@ -14980,6 +15039,9 @@ +@@ -15074,6 +15139,9 @@ 07EF07592745A8160066EA04 /* DisplayCaptureSessionManager.h */, 07EF07582745A8160066EA04 /* DisplayCaptureSessionManager.mm */, 7AFA6F682A9F57C50055322A /* DisplayLinkMac.cpp */, @@ -20974,7 +20665,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 1AFDE65B1954E8D500C48FFA /* LegacySessionStateCoding.cpp */, 0FCB4E5818BBE3D9000FCFC9 /* PageClientImplMac.h */, 0FCB4E5918BBE3D9000FCFC9 /* PageClientImplMac.mm */, -@@ -15003,6 +15065,8 @@ +@@ -15097,6 +15165,8 @@ E568B92120A3AC6A00E3C856 /* WebDataListSuggestionsDropdownMac.mm */, E55CD20124D09F1F0042DB9C /* WebDateTimePickerMac.h */, E55CD20224D09F1F0042DB9C /* WebDateTimePickerMac.mm */, @@ -20983,15 +20674,15 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 BC857E8512B71EBB00EDEB2E /* WebPageProxyMac.mm */, BC5750951268F3C6006F0F12 /* WebPopupMenuProxyMac.h */, BC5750961268F3C6006F0F12 /* WebPopupMenuProxyMac.mm */, -@@ -16050,6 +16114,7 @@ +@@ -16161,6 +16231,7 @@ 99788ACB1F421DDA00C08000 /* _WKAutomationSessionConfiguration.h in Headers */, 990D28AC1C6420CF00986977 /* _WKAutomationSessionDelegate.h in Headers */, 990D28B11C65208D00986977 /* _WKAutomationSessionInternal.h in Headers */, + D71A944A2372290B002C4D9E /* _WKBrowserInspector.h in Headers */, 5C4609E7224317B4009943C2 /* _WKContentRuleListAction.h in Headers */, 5C4609E8224317BB009943C2 /* _WKContentRuleListActionInternal.h in Headers */, - 1A5704F81BE01FF400874AF1 /* _WKContextMenuElementInfo.h in Headers */, -@@ -16355,6 +16420,7 @@ + 9B4CE9512CD99B7C00351173 /* _WKContentWorldConfiguration.h in Headers */, +@@ -16470,6 +16541,7 @@ E170876C16D6CA6900F99226 /* BlobRegistryProxy.h in Headers */, 4F601432155C5AA2001FBDE0 /* BlockingResponseMap.h in Headers */, 1A5705111BE410E600874AF1 /* BlockSPI.h in Headers */, @@ -20999,7 +20690,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 5CA9854A210BEB640057EB6B /* BrowsingWarning.h in Headers */, A7E69BCC2B2117A100D43D3F /* BufferAndBackendInfo.h in Headers */, BC3065FA1259344E00E71278 /* CacheModel.h in Headers */, -@@ -16537,7 +16603,11 @@ +@@ -16654,7 +16726,11 @@ BC14DF77120B5B7900826C0C /* InjectedBundleScriptWorld.h in Headers */, CE550E152283752200D28791 /* InsertTextOptions.h in Headers */, 9197940523DBC4BB00257892 /* InspectorBrowserAgent.h in Headers */, @@ -21011,7 +20702,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 A5E391FD2183C1F800C8FB31 /* InspectorTargetProxy.h in Headers */, C5BCE5DF1C50766A00CDE3FA /* InteractionInformationAtPosition.h in Headers */, 2D4D2C811DF60BF3002EB10C /* InteractionInformationRequest.h in Headers */, -@@ -16797,6 +16867,7 @@ +@@ -16915,6 +16991,7 @@ 0F6E7C532C4C386800F1DB85 /* RemoteDisplayListRecorderMessages.h in Headers */, F451C0FE2703B263002BA03B /* RemoteDisplayListRecorderProxy.h in Headers */, A78A5FE42B0EB39E005036D3 /* RemoteImageBufferSetIdentifier.h in Headers */, @@ -21019,7 +20710,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 2D47B56D1810714E003A3AEE /* RemoteLayerBackingStore.h in Headers */, 2DDF731518E95060004F5A66 /* RemoteLayerBackingStoreCollection.h in Headers */, 1AB16AEA164B3A8800290D62 /* RemoteLayerTreeContext.h in Headers */, -@@ -16850,6 +16921,7 @@ +@@ -16970,6 +17047,7 @@ E1E552C516AE065F004ED653 /* SandboxInitializationParameters.h in Headers */, E36FF00327F36FBD004BE21A /* SandboxStateVariables.h in Headers */, 7BAB111025DD02B3008FC479 /* ScopedActiveMessageReceiveQueue.h in Headers */, @@ -21027,7 +20718,7 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 463BB93A2B9D08D80098C5C3 /* ScriptMessageHandlerIdentifier.h in Headers */, F4E28A362C923814008120DD /* ScriptTelemetry.h in Headers */, E4D54D0421F1D72D007E3C36 /* ScrollingTreeFrameScrollingNodeRemoteIOS.h in Headers */, -@@ -17203,6 +17275,8 @@ +@@ -17323,6 +17401,8 @@ 939EF87029D112EE00F23AEE /* WebPageInlines.h in Headers */, 9197940823DBC4CB00257892 /* WebPageInspectorAgentBase.h in Headers */, A513F5402154A5D700662841 /* WebPageInspectorController.h in Headers */, @@ -21036,29 +20727,73 @@ index 9c88c517a12bbf6f81717d698754ddd2e93c0147..07c80602d45db2139cf7c2d651212e51 A543E30C215C8A8D00279CD9 /* WebPageInspectorTarget.h in Headers */, A543E30D215C8A9000279CD9 /* WebPageInspectorTargetController.h in Headers */, A543E307215AD13700279CD9 /* WebPageInspectorTargetFrontendChannel.h in Headers */, -@@ -19623,6 +19697,8 @@ +@@ -19761,7 +19841,43 @@ 522F792928D50EBB0069B45B /* HidService.mm in Sources */, 2749F6442146561B008380BF /* InjectedBundleNodeHandle.cpp in Sources */, 2749F6452146561E008380BF /* InjectedBundleRangeHandle.cpp in Sources */, + D7EB04E72372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm in Sources */, + D79902B2236E9404005D6F7E /* InspectorTargetProxyMac.mm in Sources */, - 1CC94E532AC92F190045F269 /* JSWebExtensionAPIAction.mm in Sources */, - 1C2B4D4B2A819D0D00C528A1 /* JSWebExtensionAPIAlarms.mm in Sources */, - 1C8ECFEA2AFC7DCB007BAA62 /* JSWebExtensionAPICommands.mm in Sources */, -@@ -20069,6 +20145,8 @@ - E3816B3D27E2463A005EAFC0 /* WebMockContentFilterManager.cpp in Sources */, - 31BA924D148831260062EDB5 /* WebNotificationManagerMessageReceiver.cpp in Sources */, - 2DF6FE52212E110900469030 /* WebPage.cpp in Sources */, ++ 1CC94E532AC92F190045F269 /* JSWebExtensionAPIAction.mm in Sources */, ++ 1C2B4D4B2A819D0D00C528A1 /* JSWebExtensionAPIAlarms.mm in Sources */, ++ 1C8ECFEA2AFC7DCB007BAA62 /* JSWebExtensionAPICommands.mm in Sources */, ++ 1C40052C2B2B953D00F2D9EE /* JSWebExtensionAPICookies.mm in Sources */, ++ 331102402B17B99800B21C8C /* JSWebExtensionAPIDeclarativeNetRequest.mm in Sources */, ++ 1C517F452B74393C00C46EDC /* JSWebExtensionAPIDevTools.mm in Sources */, ++ 1C517F432B74393C00C46EDC /* JSWebExtensionAPIDevToolsExtensionPanel.mm in Sources */, ++ 1C517F472B74393C00C46EDC /* JSWebExtensionAPIDevToolsInspectedWindow.mm in Sources */, ++ 1C517F462B74393C00C46EDC /* JSWebExtensionAPIDevToolsNetwork.mm in Sources */, ++ 1C517F412B74393C00C46EDC /* JSWebExtensionAPIDevToolsPanels.mm in Sources */, ++ B6114A7F29394A1600380B1B /* JSWebExtensionAPIEvent.mm in Sources */, ++ 1C5DC471290B33A20061EC62 /* JSWebExtensionAPIExtension.mm in Sources */, ++ B6CCAAB929A445E90092E846 /* JSWebExtensionAPILocalization.mm in Sources */, ++ 1CCEE4532B0989FC0034E059 /* JSWebExtensionAPIMenus.mm in Sources */, ++ 1C5DC4552908AC900061EC62 /* JSWebExtensionAPINamespace.mm in Sources */, ++ 1C386F362AF409F9004108F0 /* JSWebExtensionAPINotifications.mm in Sources */, ++ B61AFA4929510D0F008220B1 /* JSWebExtensionAPIPermissions.mm in Sources */, ++ 1C9A15CF2ABDF1E2002CC12A /* JSWebExtensionAPIPort.mm in Sources */, ++ 1C5DC472290B33A60061EC62 /* JSWebExtensionAPIRuntime.mm in Sources */, ++ B63E9A6F2AAF2B2D005F4561 /* JSWebExtensionAPIScripting.mm in Sources */, ++ 029D6BB22C407AA30068CF99 /* JSWebExtensionAPISidebarAction.mm in Sources */, ++ 029D6BB12C407AA30068CF99 /* JSWebExtensionAPISidePanel.mm in Sources */, ++ B63C10342B51C0B6004A69B8 /* JSWebExtensionAPIStorage.mm in Sources */, ++ B63C10372B51C102004A69B8 /* JSWebExtensionAPIStorageArea.mm in Sources */, ++ 1C5ACFAB2A96F8D500C041C0 /* JSWebExtensionAPITabs.mm in Sources */, ++ 1C15497F2926C073001B9E5B /* JSWebExtensionAPITest.mm in Sources */, + 1C0F05BE2CFA5D2E007D1F62 /* JSWebExtensionAPIUnified.mm in Sources */, ++ 3375A3772942A19D0028536D /* JSWebExtensionAPIWebNavigation.mm in Sources */, ++ 33F68338293FF6F5005C63C0 /* JSWebExtensionAPIWebNavigationEvent.mm in Sources */, ++ B63A99772B7EA002004611FD /* JSWebExtensionAPIWebPageNamespace.mm in Sources */, ++ B63A99782B7EA002004611FD /* JSWebExtensionAPIWebPageRuntime.mm in Sources */, ++ 3399E1532B59EFD7008BFB60 /* JSWebExtensionAPIWebRequest.mm in Sources */, ++ 337042022B58A0B70077FF78 /* JSWebExtensionAPIWebRequestEvent.mm in Sources */, ++ 1C5ACFA62A96F8C400C041C0 /* JSWebExtensionAPIWindows.mm in Sources */, ++ 1C5ACFA72A96F8C400C041C0 /* JSWebExtensionAPIWindowsEvent.mm in Sources */, + 1C5DC45F2909B05A0061EC62 /* JSWebExtensionWrapperCocoa.mm in Sources */, + C14D37FE24ACE086007FF014 /* LaunchServicesDatabaseManager.mm in Sources */, + C1710CF724AA643200D7C112 /* LaunchServicesDatabaseObserver.mm in Sources */, +@@ -20010,6 +20126,8 @@ + FAE61CEB2D0A5608000D238D /* UnifiedSource135.cpp in Sources */, + FAE61CE82D0A5608000D238D /* UnifiedSource136.cpp in Sources */, + FAE61CEA2D0A5608000D238D /* UnifiedSource137.cpp in Sources */, ++ FAE61CED2D0A5608000D238D /* UnifiedSource138.cpp in Sources */, ++ FAE61CEE2D0A5608000D238D /* UnifiedSource139.cpp in Sources */, + 078B04442CF1149200B453A6 /* URLSchemeHandler.swift in Sources */, + 078B04B62CF2B4D300B453A6 /* View+WebViewModifiers.swift in Sources */, + 52CDC5C62731DA0D00A3E3EB /* VirtualAuthenticatorManager.cpp in Sources */, +@@ -20117,6 +20235,8 @@ + 078B04A02CF18EAB00B453A6 /* WebPage+NavigationPreferences.swift in Sources */, + 07A58C882D068CAE00CAB4ED /* WebPage+SwiftUI.swift in Sources */, + 07CB79962CE9435700199C49 /* WebPage.swift in Sources */, + D79902B1236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm in Sources */, + D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */, - C0CE72A01247E71D00BC0EC4 /* WebPageMessageReceiver.cpp in Sources */, - BCBD3914125BB1A800D2C29F /* WebPageProxyMessageReceiver.cpp in Sources */, - C0CE72A01B47E71D00BC0EC4 /* WebPageTestingMessageReceiver.cpp in Sources */, + 7CE9CE101FA0767A000177DE /* WebPageUpdatePreferences.cpp in Sources */, + 7CEB00DD1FA69ABE0065473B /* WebPreferencesFeatures.cpp in Sources */, + 7CF1907125338F3800ABE183 /* WebPreferencesGetterSetters.cpp in Sources */, diff --git a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp -index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d9143afd03a 100644 +index 0037482f26f39ef4404dd660091b9be1c92c7b91..ae3523342a8cc44d9add5358171141b2d994a878 100644 --- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp +++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp -@@ -236,6 +236,11 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou +@@ -248,6 +248,11 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou } #endif @@ -21070,7 +20805,7 @@ index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d91 #if ENABLE(PDFJS) if (tryLoadingUsingPDFJSHandler(resourceLoader, trackingParameters)) return; -@@ -245,12 +250,16 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou +@@ -257,12 +262,16 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou return; if (InspectorInstrumentationWebKit::shouldInterceptRequest(resourceLoader)) { @@ -21092,8 +20827,8 @@ index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d91 + } } - WEBLOADERSTRATEGY_RELEASE_LOG("scheduleLoad: URL will be scheduled with the NetworkProcess"); -@@ -369,7 +378,8 @@ static void addParametersShared(const LocalFrame* frame, NetworkResourceLoadPara + WEBLOADERSTRATEGY_RELEASE_LOG_FORWARDABLE(WEBLOADERSTRATEGY_SCHEDULELOAD); +@@ -382,7 +391,8 @@ static void addParametersShared(const LocalFrame* frame, NetworkResourceLoadPara parameters.linkPreconnectEarlyHintsEnabled = mainFrame->settings().linkPreconnectEarlyHintsEnabled(); } @@ -21103,7 +20838,7 @@ index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d91 { auto identifier = *resourceLoader.identifier(); -@@ -384,7 +394,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL +@@ -397,7 +407,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL RunLoop::main().dispatch([resourceLoader = Ref { resourceLoader }, error = blockedError(request)] { resourceLoader->didFail(error); }); @@ -21112,7 +20847,7 @@ index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d91 } } -@@ -394,7 +404,6 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL +@@ -407,7 +417,6 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, url '%s' will be scheduled with the NetworkProcess with priority %d, storedCredentialsPolicy %i", resourceLoader.url().string().latin1().data(), static_cast(resourceLoader.request().priority()), (int)storedCredentialsPolicy); @@ -21120,7 +20855,7 @@ index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d91 loadParameters.identifier = identifier; loadParameters.webPageProxyID = trackingParameters.webPageProxyID; loadParameters.webPageID = trackingParameters.pageID; -@@ -484,14 +493,11 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL +@@ -497,14 +506,11 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL if (loadParameters.options.mode != FetchOptions::Mode::Navigate) { ASSERT(loadParameters.sourceOrigin); @@ -21138,7 +20873,7 @@ index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d91 loadParameters.isMainFrameNavigation = isMainFrameNavigation; if (loadParameters.isMainFrameNavigation && document) -@@ -532,6 +538,17 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL +@@ -545,6 +551,17 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL } ASSERT((loadParameters.webPageID && loadParameters.webFrameID) || loadParameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials); @@ -21156,7 +20891,7 @@ index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d91 std::optional existingNetworkResourceLoadIdentifierToResume; if (loadParameters.isMainFrameNavigation) -@@ -547,7 +564,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL +@@ -560,7 +577,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL } auto loader = WebResourceLoader::create(resourceLoader, trackingParameters); @@ -21165,7 +20900,7 @@ index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d91 } void WebLoaderStrategy::scheduleInternallyFailedLoad(WebCore::ResourceLoader& resourceLoader) -@@ -957,7 +974,7 @@ void WebLoaderStrategy::didFinishPreconnection(WebCore::ResourceLoaderIdentifier +@@ -970,7 +987,7 @@ void WebLoaderStrategy::didFinishPreconnection(WebCore::ResourceLoaderIdentifier bool WebLoaderStrategy::isOnLine() const { @@ -21174,7 +20909,7 @@ index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d91 } void WebLoaderStrategy::addOnlineStateChangeListener(Function&& listener) -@@ -984,6 +1001,11 @@ void WebLoaderStrategy::isResourceLoadFinished(CachedResource& resource, Complet +@@ -997,6 +1014,11 @@ void WebLoaderStrategy::isResourceLoadFinished(CachedResource& resource, Complet void WebLoaderStrategy::setOnLineState(bool isOnLine) { @@ -21186,7 +20921,7 @@ index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d91 if (m_isOnLine == isOnLine) return; -@@ -992,6 +1014,12 @@ void WebLoaderStrategy::setOnLineState(bool isOnLine) +@@ -1005,6 +1027,12 @@ void WebLoaderStrategy::setOnLineState(bool isOnLine) listener(isOnLine); } @@ -21200,18 +20935,18 @@ index d2b9d07144dab5d57cf91942d55a2b140a802d7f..4ad2d136a352af588c2c3efa8e470d91 { WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetCaptureExtraNetworkLoadMetricsEnabled(enabled), 0); diff --git a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h -index 1a106f701e2756b5b5e19f828f97a7c0b838ae19..3ccc019ea234c414129f6c1209574f3b0387aa9f 100644 +index a835521fae8043c1c3d6202288b0c3a9f92aa81b..0c8bee6c0a02e6adb1b9e56d77613253111fffd2 100644 --- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h +++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h -@@ -43,6 +43,7 @@ struct FetchOptions; +@@ -44,6 +44,7 @@ struct FetchOptions; namespace WebKit { class NetworkProcessConnection; +class NetworkResourceLoadParameters; class WebFrame; class WebPage; - class WebURLSchemeTaskProxy; -@@ -91,6 +92,9 @@ public: + class WebProcess; +@@ -96,6 +97,9 @@ public: bool isOnLine() const final; void addOnlineStateChangeListener(Function&&) final; void setOnLineState(bool); @@ -21221,7 +20956,7 @@ index 1a106f701e2756b5b5e19f828f97a7c0b838ae19..3ccc019ea234c414129f6c1209574f3b void setExistingNetworkResourceLoadIdentifierToResume(std::optional existingNetworkResourceLoadIdentifierToResume) { m_existingNetworkResourceLoadIdentifierToResume = existingNetworkResourceLoadIdentifierToResume; } -@@ -143,6 +147,7 @@ private: +@@ -149,6 +153,7 @@ private: Vector> m_onlineStateChangeListeners; std::optional m_existingNetworkResourceLoadIdentifierToResume; bool m_isOnLine { true }; @@ -21230,10 +20965,10 @@ index 1a106f701e2756b5b5e19f828f97a7c0b838ae19..3ccc019ea234c414129f6c1209574f3b } // namespace WebKit diff --git a/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp b/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp -index c28454bdba0426c66f1f24c854761b2ddd0354a0..ee73825ca10881ebd8099af5382b7cb5c7efc882 100644 +index 069e870734e40672966b7ee5853a5469de826c40..ddeca40ad670d397f07d9064cfe90caefcdaaa5a 100644 --- a/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp +++ b/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp -@@ -189,9 +189,6 @@ void WebResourceLoader::didReceiveResponse(ResourceResponse&& response, PrivateR +@@ -188,9 +188,6 @@ void WebResourceLoader::didReceiveResponse(ResourceResponse&& response, PrivateR } m_coreLoader->didReceiveResponse(inspectorResponse, [this, protectedThis = WTFMove(protectedThis), interceptedRequestIdentifier, policyDecisionCompletionHandler = WTFMove(policyDecisionCompletionHandler), overrideData = WTFMove(overrideData)]() mutable { @@ -21243,7 +20978,7 @@ index c28454bdba0426c66f1f24c854761b2ddd0354a0..ee73825ca10881ebd8099af5382b7cb5 if (!m_coreLoader || !m_coreLoader->identifier()) { m_interceptController.continueResponse(interceptedRequestIdentifier); return; -@@ -209,6 +206,8 @@ void WebResourceLoader::didReceiveResponse(ResourceResponse&& response, PrivateR +@@ -208,6 +205,8 @@ void WebResourceLoader::didReceiveResponse(ResourceResponse&& response, PrivateR } }); }); @@ -21252,24 +20987,11 @@ index c28454bdba0426c66f1f24c854761b2ddd0354a0..ee73825ca10881ebd8099af5382b7cb5 return; } -diff --git a/Source/WebKit/WebProcess/Notifications/NotificationPermissionRequestManager.cpp b/Source/WebKit/WebProcess/Notifications/NotificationPermissionRequestManager.cpp -index e314c2987e348a0abee8b655caff3a1c3b3c4564..882746d581bd8db6f2fad5944f09ee9fe9e0e55b 100644 ---- a/Source/WebKit/WebProcess/Notifications/NotificationPermissionRequestManager.cpp -+++ b/Source/WebKit/WebProcess/Notifications/NotificationPermissionRequestManager.cpp -@@ -85,7 +85,7 @@ void NotificationPermissionRequestManager::startRequest(const SecurityOriginData - - m_page->sendWithAsyncReply(Messages::WebPageProxy::RequestNotificationPermission(securityOrigin.toString()), [this, protectedThis = Ref { *this }, securityOrigin, permissionHandler = WTFMove(permissionHandler)](bool allowed) mutable { - -- auto innerPermissionHandler = [this, protectedThis = Ref { *this }, securityOrigin, permissionHandler = WTFMove(permissionHandler)] (bool allowed) mutable { -+ auto innerPermissionHandler = [this, protectedThis, securityOrigin, permissionHandler = WTFMove(permissionHandler)] (bool allowed) mutable { - WebProcess::singleton().supplement()->didUpdateNotificationDecision(securityOrigin.toString(), allowed); - - auto permissionHandlers = m_requestsPerOrigin.take(securityOrigin); diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp -index 39cd00b233c10fc167feed68802b9930bf88e7ca..0e1cd22bdebf9d57074d264104843ca76e820b98 100644 +index 5806d017fb7aedd8c6540c7868440f18994e6239..779ab16cd8004f47348c7e5acf6b18eeeefd7141 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp -@@ -476,6 +476,8 @@ void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel lev +@@ -481,6 +481,8 @@ void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel lev { // Notify the bundle client. auto page = protectedPage(); @@ -21279,20 +21001,10 @@ index 39cd00b233c10fc167feed68802b9930bf88e7ca..0e1cd22bdebf9d57074d264104843ca7 } diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp -index dd03326b1ad54e1d363d722cfe86bb779fbeead1..71ab72cdff9870dbf9fc017e8e61ab73e1437262 100644 +index dd03326b1ad54e1d363d722cfe86bb779fbeead1..f54d631dc4034c995cbd74ec6b545c3c7dd25990 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp -@@ -30,6 +30,9 @@ - - #include "WebPage.h" - #include -+#include -+#include -+#include - - namespace WebKit { - using namespace WebCore; -@@ -53,7 +56,7 @@ OptionSet WebDragClient::dragSourceActionMaskForPoint(const In +@@ -53,7 +53,7 @@ OptionSet WebDragClient::dragSourceActionMaskForPoint(const In return m_page->allowedDragSourceActions(); } @@ -21301,30 +21013,11 @@ index dd03326b1ad54e1d363d722cfe86bb779fbeead1..71ab72cdff9870dbf9fc017e8e61ab73 void WebDragClient::startDrag(DragItem, DataTransfer&, Frame&) { } -diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp -index 698a9701706dc8d6772f6565ae39c454fe8bf641..cafbb07349e175f786e3450a2132683e80273217 100644 ---- a/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp -+++ b/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp -@@ -1581,14 +1581,6 @@ void WebLocalFrameLoaderClient::transitionToCommittedForNewPage(InitializingIfra - - if (initializingIframe == InitializingIframe::No) - webPage->scheduleFullEditorStateUpdate(); -- --#if USE(COORDINATED_GRAPHICS) -- if (shouldUseFixedLayout) { -- view->setDelegatedScrollingMode(shouldUseFixedLayout ? DelegatedScrollingMode::DelegatedToNativeScrollView : DelegatedScrollingMode::NotDelegated); -- view->setPaintsEntireContents(shouldUseFixedLayout); -- return; -- } --#endif - } - - void WebLocalFrameLoaderClient::didRestoreFromBackForwardCache() diff --git a/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm b/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm -index 69b851554679018aefe2c22b79671f7796d9e8b8..50e985ded3cdc9aaa5f30f7776c29cbc23c2b2b8 100644 +index 2713e431893efd17c95d163f14aec45b27e0d6fc..b96b1d9cba20af611837915412fa4202667e800d 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm +++ b/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm -@@ -129,7 +129,8 @@ static WebCore::CachedImage* cachedImage(Element& element) +@@ -128,7 +128,8 @@ static WebCore::CachedImage* cachedImage(Element& element) void WebDragClient::declareAndWriteDragImage(const String& pasteboardName, Element& element, const URL& url, const String& label, LocalFrame*) { @@ -21461,7 +21154,7 @@ index 0000000000000000000000000000000000000000..226b3bf6bd83d2606a0aeb627ae9302f + +#endif // ENABLE(DRAG_SUPPORT) diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp -index 3faeacda3c578ef2fd86e4a04b09315017dc47f1..174c8d565a00a519e12510c77fff4cfb63cc7a8a 100644 +index 85e70183ddc4805c835b4ffc5daf40ca930536de..2483f638a31d96345993f824a3b5967379bab103 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp @@ -39,6 +39,7 @@ @@ -21472,24 +21165,7 @@ index 3faeacda3c578ef2fd86e4a04b09315017dc47f1..174c8d565a00a519e12510c77fff4cfb #include #include #include -@@ -103,6 +104,16 @@ void DrawingAreaCoordinatedGraphics::scroll(const IntRect& scrollRect, const Int - ASSERT(m_scrollRect.isEmpty()); - ASSERT(m_scrollOffset.isEmpty()); - ASSERT(m_dirtyRegion.isEmpty()); -+// Playwright begin -+#if !PLATFORM(WIN) -+ if (m_webPage->mainFrameView() && m_webPage->mainFrameView()->useFixedLayout()) { -+ IntRect visibleRect = IntRect(m_layerTreeHost->viewportController().visibleContentsRect()); -+ visibleRect.move(-scrollDelta.width(), -scrollDelta.height()); -+ m_layerTreeHost->scrollNonCompositedContents(visibleRect); -+ return; -+ } -+#endif -+// Playwright end - m_layerTreeHost->scrollNonCompositedContents(scrollRect); - return; - } -@@ -566,6 +577,11 @@ void DrawingAreaCoordinatedGraphics::enterAcceleratedCompositingMode(GraphicsLay +@@ -565,6 +566,11 @@ void DrawingAreaCoordinatedGraphics::enterAcceleratedCompositingMode(GraphicsLay m_scrollOffset = IntSize(); m_displayTimer.stop(); m_isWaitingForDidUpdate = false; @@ -21501,7 +21177,7 @@ index 3faeacda3c578ef2fd86e4a04b09315017dc47f1..174c8d565a00a519e12510c77fff4cfb } void DrawingAreaCoordinatedGraphics::sendEnterAcceleratedCompositingModeIfNeeded() -@@ -623,6 +639,11 @@ void DrawingAreaCoordinatedGraphics::exitAcceleratedCompositingMode() +@@ -622,6 +628,11 @@ void DrawingAreaCoordinatedGraphics::exitAcceleratedCompositingMode() // UI process, we still need to let it know about the new contents, so send an Update message. send(Messages::DrawingAreaProxy::Update(0, WTFMove(updateInfo))); } @@ -21513,58 +21189,38 @@ index 3faeacda3c578ef2fd86e4a04b09315017dc47f1..174c8d565a00a519e12510c77fff4cfb } void DrawingAreaCoordinatedGraphics::scheduleDisplay() -diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp -index cc48ff93f937051121c38776e3c5c74ed6d70e8a..722dbdb4a881404f00a7e65e3e092f4873bde093 100644 ---- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp -+++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp -@@ -205,8 +205,16 @@ void LayerTreeHost::scrollNonCompositedContents(const IntRect& rect) - m_scrolledSinceLastFrame = true; - - auto* frameView = m_webPage.localMainFrameView(); -+ -+// Playwright begin -+#if PLATFORM(WIN) - if (!frameView || !frameView->delegatesScrolling()) -+ return -+#else -+ if (!frameView) - return; -+#endif -+// Playwright end - - m_viewportController.didScroll(rect.location()); - didChangeViewport(); -@@ -327,6 +335,10 @@ void LayerTreeHost::didChangeViewport() - - if (!view->useFixedLayout()) - view->notifyScrollPositionChanged(m_lastScrollPosition); -+// Playwright begin -+ else -+ m_viewportController.didScroll(m_lastScrollPosition); -+// Playwright end - } - - if (m_lastPageScaleFactor != pageScale) { diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h -index ea6ae1b9beff5a6bd4cbc7d52bcfa6da71a5b86b..efcdea566c836bcee32ff93546ee8a845dbe176b 100644 +index 815e10e285c0f88d7bc3a70fe71f07106873cb30..75cd3642c43c506afd814014f5d31dff8c260578 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h -@@ -117,6 +117,13 @@ public: +@@ -135,6 +135,7 @@ public: #if PLATFORM(WPE) && USE(GBM) && ENABLE(WPE_PLATFORM) void preferredBufferFormatsDidChange(); #endif -+ -+// Playwright begin -+#if USE(COORDINATED_GRAPHICS) -+ const SimpleViewportController& viewportController() const { return m_viewportController; } -+#endif -+// Playwright end + private: - #if USE(COORDINATED_GRAPHICS) - void layerFlushTimerFired(); + void updateRootLayer(); + WebCore::FloatRect visibleContentsRect() const; +diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/ThreadedCompositor.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/ThreadedCompositor.cpp +index 99cecc2252ea05a81acf42281225c7000cda0509..91c967238b6b359e1c96663d95550c5ba7728386 100644 +--- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/ThreadedCompositor.cpp ++++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/ThreadedCompositor.cpp +@@ -296,7 +296,13 @@ void ThreadedCompositor::renderLayerTree() + // and similarly all GL operations are done inside that specific scope. + + if (needsResize) ++#if PLATFORM(WPE) ++ RunLoop::main().dispatch([this, protectedThis = Ref { *this }, viewportSize] { ++ m_surface->clientResize(viewportSize); ++ }); ++#else + m_surface->clientResize(viewportSize); ++#endif + + m_surface->willRenderFrame(); + RunLoop::main().dispatch([this, protectedThis = Ref { *this }] { diff --git a/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp b/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp -index 98f4dbab8521e1677047713093614d5ff6cb886f..e24a67b67bf9f1af419c98ecfb3e7ae034751c32 100644 +index 428e10e8311dfb3201439688f5ad35a4d609b95c..b03ccee5c7057875092607d01b72265d63a2cfd9 100644 --- a/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp +++ b/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp @@ -27,6 +27,7 @@ @@ -21590,10 +21246,10 @@ index 98f4dbab8521e1677047713093614d5ff6cb886f..e24a67b67bf9f1af419c98ecfb3e7ae0 { if (m_hasRemovedMessageReceiver) diff --git a/Source/WebKit/WebProcess/WebPage/DrawingArea.h b/Source/WebKit/WebProcess/WebPage/DrawingArea.h -index c93d6787d88298575059259d2d45826e9d23c44b..3d42c0d9625e6c976f7cacda4bffcdf5c65b7217 100644 +index a124c32b48b43f4f6b3d4e95f4a7ca6906412026..5583b767ff16f3af735ee0e657a816c0ccb2e298 100644 --- a/Source/WebKit/WebProcess/WebPage/DrawingArea.h +++ b/Source/WebKit/WebProcess/WebPage/DrawingArea.h -@@ -165,6 +165,9 @@ public: +@@ -166,6 +166,9 @@ public: virtual bool enterAcceleratedCompositingModeIfNeeded() = 0; virtual void backgroundColorDidChange() { }; #endif @@ -21604,7 +21260,7 @@ index c93d6787d88298575059259d2d45826e9d23c44b..3d42c0d9625e6c976f7cacda4bffcdf5 #if PLATFORM(WPE) && USE(GBM) && ENABLE(WPE_PLATFORM) virtual void preferredBufferFormatsDidChange() { } diff --git a/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp b/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp -index 2a79682f5d837df439d4b18805a695d48341bd56..6423f2a8aa1fe0af5e2a4073f96538fde67b765c 100644 +index 0fec14223997c3f22758e78bda6640dfa1865c65..31161fdf651dbacd18e9789218d797e0140ca781 100644 --- a/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp @@ -44,6 +44,7 @@ @@ -21615,7 +21271,7 @@ index 2a79682f5d837df439d4b18805a695d48341bd56..6423f2a8aa1fe0af5e2a4073f96538fd #include #include #include -@@ -429,6 +430,12 @@ void WebCookieJar::removeChangeListener(const String& host, const WebCore::Cooki +@@ -455,6 +456,12 @@ void WebCookieJar::removeChangeListener(const String& host, const WebCore::Cooki } #endif @@ -21629,10 +21285,10 @@ index 2a79682f5d837df439d4b18805a695d48341bd56..6423f2a8aa1fe0af5e2a4073f96538fd String WebCookieJar::cookiesInPartitionedCookieStorage(const WebCore::Document&, const URL&, const WebCore::SameSiteInfo&) const diff --git a/Source/WebKit/WebProcess/WebPage/WebCookieJar.h b/Source/WebKit/WebProcess/WebPage/WebCookieJar.h -index a050f15e1a9295ffccb46cb1b4fd801750f8ac33..49e28dceccb19d15149e54913fcc00b0544e9a7a 100644 +index 001207c6c6a651707aa91899536b5cf715047e3f..afe3874d9c6b41f19af4144597557e2abd309f71 100644 --- a/Source/WebKit/WebProcess/WebPage/WebCookieJar.h +++ b/Source/WebKit/WebProcess/WebPage/WebCookieJar.h -@@ -74,6 +74,8 @@ public: +@@ -76,6 +76,8 @@ public: void clearCache() final; @@ -21642,10 +21298,10 @@ index a050f15e1a9295ffccb46cb1b4fd801750f8ac33..49e28dceccb19d15149e54913fcc00b0 WebCookieJar(); diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp -index f37c00d9bdbdc7754ce8bd75c1be645617a3e019..9242983dfaccb87fb55e8126a1c903c042cb480d 100644 +index ad8d14f45c5b0719836f8d7faae07bfcac3823b8..50c20d09b7465b218ee3154377a0306c1cb279fe 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp -@@ -236,6 +236,7 @@ +@@ -239,6 +239,7 @@ #include #include #include @@ -21653,17 +21309,20 @@ index f37c00d9bdbdc7754ce8bd75c1be645617a3e019..9242983dfaccb87fb55e8126a1c903c0 #include #include #include -@@ -1078,6 +1079,9 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters) +@@ -1137,6 +1138,12 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters) + setLinkDecorationFilteringData(WTFMove(parameters.linkDecorationFilteringData)); + setAllowedQueryParametersForAdvancedPrivacyProtections(WTFMove(parameters.allowedQueryParametersForAdvancedPrivacyProtections)); #endif - #endif // HAVE(SANDBOX_STATE_FLAGS) - ++ // For popup windows WebPage::Show() maybe called in the next lines from the constructor, ++ // at which point the page is not in the WebProcess's map yet and it is not safe to ++ // dispatch nested message loop and receive IPC messages. To mitigate that, the actual ++ // pause is postponed until the page is added to the map. + if (parameters.shouldPauseInInspectorWhenShown) -+ m_page->inspectorController().pauseWhenShown(); -+ - updateThrottleState(); - #if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) - updateImageAnimationEnabled(); -@@ -2043,6 +2047,22 @@ void WebPage::loadDidCommitInAnotherProcess(WebCore::FrameIdentifier frameID, st ++ m_page->inspectorController().pauseOnStart(parameters.windowFeatures ? InspectorController::PauseCondition::WHEN_CREATION_FINISHED : InspectorController::PauseCondition::WHEN_SHOWN); + if (parameters.windowFeatures) { + m_page->applyWindowFeatures(*parameters.windowFeatures); + m_page->chrome().show(); +@@ -2098,6 +2105,22 @@ void WebPage::loadDidCommitInAnotherProcess(WebCore::FrameIdentifier frameID, st frame->loadDidCommitInAnotherProcess(layerHostingContextIdentifier); } @@ -21685,8 +21344,8 @@ index f37c00d9bdbdc7754ce8bd75c1be645617a3e019..9242983dfaccb87fb55e8126a1c903c0 + void WebPage::loadRequest(LoadParameters&& loadParameters) { - WEBPAGE_RELEASE_LOG(Loading, "loadRequest: navigationID=%" PRIu64 ", shouldTreatAsContinuingLoad=%u, lastNavigationWasAppInitiated=%d, existingNetworkResourceLoadIdentifierToResume=%" PRIu64, loadParameters.navigationID ? loadParameters.navigationID->toUInt64() : 0, static_cast(loadParameters.shouldTreatAsContinuingLoad), loadParameters.request.isAppInitiated(), valueOrDefault(loadParameters.existingNetworkResourceLoadIdentifierToResume).toUInt64()); -@@ -2238,7 +2258,9 @@ void WebPage::stopLoading() + WEBPAGE_RELEASE_LOG(Loading, "loadRequest: navigationID=%" PRIu64 ", shouldTreatAsContinuingLoad=%u, lastNavigationWasAppInitiated=%d, existingNetworkResourceLoadIdentifierToResume=%" PRIu64, loadParameters.navigationID ? loadParameters.navigationID->toUInt64() : 0, static_cast(loadParameters.shouldTreatAsContinuingLoad), loadParameters.request.isAppInitiated(), loadParameters.existingNetworkResourceLoadIdentifierToResume ? loadParameters.existingNetworkResourceLoadIdentifierToResume->toUInt64() : 0); +@@ -2293,7 +2316,9 @@ void WebPage::stopLoading() void WebPage::stopLoadingDueToProcessSwap() { SetForScope isStoppingLoadingDueToProcessSwap(m_isStoppingLoadingDueToProcessSwap, true); @@ -21696,90 +21355,17 @@ index f37c00d9bdbdc7754ce8bd75c1be645617a3e019..9242983dfaccb87fb55e8126a1c903c0 } bool WebPage::defersLoading() const -@@ -2339,17 +2361,14 @@ void WebPage::setSize(const WebCore::IntSize& viewSize) - view->resize(viewSize); - m_drawingArea->setNeedsDisplay(); - --#if USE(COORDINATED_GRAPHICS) - if (view->useFixedLayout()) - sendViewportAttributesChanged(m_page->viewportArguments()); --#endif - - #if ENABLE(ACCESSIBILITY_ISOLATED_TREE) - cacheAXSize(m_viewSize); - #endif - } - --#if USE(COORDINATED_GRAPHICS) - void WebPage::sendViewportAttributesChanged(const ViewportArguments& viewportArguments) - { - RefPtr localMainFrame = dynamicDowncast(m_page->mainFrame()); -@@ -2374,20 +2393,18 @@ void WebPage::sendViewportAttributesChanged(const ViewportArguments& viewportArg - - ViewportAttributes attr = computeViewportAttributes(viewportArguments, minimumLayoutFallbackWidth, deviceWidth, deviceHeight, 1, m_viewSize); - -- // If no layout was done yet set contentFixedOrigin to (0,0). -- IntPoint contentFixedOrigin = view->didFirstLayout() ? view->fixedVisibleContentRect().location() : IntPoint(); -- -- // Put the width and height to the viewport width and height. In css units however. -- // Use FloatSize to avoid truncated values during scale. -- FloatSize contentFixedSize = m_viewSize; -- -- contentFixedSize.scale(1 / attr.initialScale); -- view->setFixedVisibleContentRect(IntRect(contentFixedOrigin, roundedIntSize(contentFixedSize))); -+#if ENABLE(CSS_DEVICE_ADAPTATION) -+ FrameView* view = m_page->mainFrame().view(); -+ // CSS viewport descriptors might be applied to already affected viewport size -+ // if the page enables/disables stylesheets, so need to keep initial viewport size. -+ view->setInitialViewportSize(roundedIntSize(m_viewSize)); -+#endif - - attr.initialScale = m_page->viewportArguments().zoom; // Resets auto (-1) if no value was set by user. - - // This also takes care of the relayout. - setFixedLayoutSize(roundedIntSize(attr.layoutSize)); -+ scaleView(deviceWidth / attr.layoutSize.width()); - - #if USE(COORDINATED_GRAPHICS) - m_drawingArea->didChangeViewportAttributes(WTFMove(attr)); -@@ -2395,7 +2412,6 @@ void WebPage::sendViewportAttributesChanged(const ViewportArguments& viewportArg - send(Messages::WebPageProxy::DidChangeViewportProperties(attr)); - #endif - } --#endif - - void WebPage::drawRect(GraphicsContext& graphicsContext, const IntRect& rect) - { -@@ -2686,6 +2702,7 @@ void WebPage::scaleView(double scale) - } - - m_page->setViewScaleFactor(scale); -+ send(Messages::WebPageProxy::ViewScaleFactorDidChange(scale)); - scalePage(pageScale, scrollPositionAtNewScale); - } - -@@ -2865,18 +2882,14 @@ void WebPage::viewportPropertiesDidChange(const ViewportArguments& viewportArgum +@@ -2879,7 +2904,7 @@ void WebPage::viewportPropertiesDidChange(const ViewportArguments& viewportArgum + #if PLATFORM(IOS_FAMILY) + if (m_viewportConfiguration.setViewportArguments(viewportArguments)) viewportConfigurationChanged(); - #endif - --#if USE(COORDINATED_GRAPHICS) - RefPtr localMainFrame = dynamicDowncast(m_page->mainFrame()); +-#elif PLATFORM(GTK) || PLATFORM(WPE) ++#elif PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN) || PLATFORM(MAC) + // Adjust view dimensions when using fixed layout. + RefPtr localMainFrame = this->localMainFrame(); RefPtr view = localMainFrame ? localMainFrame->view() : nullptr; - if (view && view->useFixedLayout()) - sendViewportAttributesChanged(viewportArguments); -+#if USE(COORDINATED_GRAPHICS) - else - m_drawingArea->didChangeViewportAttributes(ViewportAttributes()); - #endif -- --#if !PLATFORM(IOS_FAMILY) && !USE(COORDINATED_GRAPHICS) -- UNUSED_PARAM(viewportArguments); --#endif - } - - #if !PLATFORM(IOS_FAMILY) -@@ -3594,6 +3607,13 @@ void WebPage::setLastKnownMousePosition(WebCore::FrameIdentifier frameID, IntPoi - frame->coreLocalFrame()->eventHandler().setLastKnownMousePosition(eventPoint, globalPoint); +@@ -3657,6 +3682,13 @@ void WebPage::flushDeferredScrollEvents() + corePage()->flushDeferredScrollEvents(); } +#if ENABLE(ORIENTATION_EVENTS) @@ -21792,7 +21378,7 @@ index f37c00d9bdbdc7754ce8bd75c1be645617a3e019..9242983dfaccb87fb55e8126a1c903c0 void WebPage::flushDeferredDidReceiveMouseEvent() { if (auto info = std::exchange(m_deferredDidReceiveMouseEvent, std::nullopt)) -@@ -3878,6 +3898,97 @@ void WebPage::touchEvent(const WebTouchEvent& touchEvent, CompletionHandlersendMessageToTargetBackend(targetId, message); } @@ -21898,19 +21484,24 @@ index f37c00d9bdbdc7754ce8bd75c1be645617a3e019..9242983dfaccb87fb55e8126a1c903c0 +{ + m_page->inspectorController().resumeIfPausedInNewWindow(); +} ++ ++void WebPage::didAddWebPageToWebProcess() ++{ ++ m_page->inspectorController().didFinishPageCreation(); ++} + void WebPage::insertNewlineInQuotedContent() { RefPtr frame = m_page->checkedFocusController()->focusedOrMainFrame(); -@@ -4206,6 +4322,7 @@ void WebPage::didCompletePageTransition() +@@ -4247,6 +4380,7 @@ void WebPage::didCompletePageTransition() void WebPage::show() { send(Messages::WebPageProxy::ShowPage()); -+ m_page->inspectorController().didShowNewWindow(); ++ m_page->inspectorController().didShowPage(); } void WebPage::setIsTakingSnapshotsForApplicationSuspension(bool isTakingSnapshotsForApplicationSuspension) -@@ -5364,7 +5481,7 @@ NotificationPermissionRequestManager* WebPage::notificationPermissionRequestMana +@@ -5417,7 +5551,7 @@ NotificationPermissionRequestManager* WebPage::notificationPermissionRequestMana #if ENABLE(DRAG_SUPPORT) @@ -21919,7 +21510,7 @@ index f37c00d9bdbdc7754ce8bd75c1be645617a3e019..9242983dfaccb87fb55e8126a1c903c0 void WebPage::performDragControllerAction(DragControllerAction action, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet draggingSourceOperationMask, SelectionData&& selectionData, OptionSet flags, CompletionHandler, DragHandlingMethod, bool, unsigned, IntRect, IntRect, std::optional)>&& completionHandler) { if (!m_page) -@@ -7764,6 +7881,10 @@ void WebPage::didCommitLoad(WebFrame* frame) +@@ -7879,6 +8013,10 @@ void WebPage::didCommitLoad(WebFrame* frame) #endif flushDeferredDidReceiveMouseEvent(); @@ -21930,9 +21521,9 @@ index f37c00d9bdbdc7754ce8bd75c1be645617a3e019..9242983dfaccb87fb55e8126a1c903c0 } void WebPage::didFinishDocumentLoad(WebFrame& frame) -@@ -8047,6 +8168,9 @@ Ref WebPage::createDocumentLoader(LocalFrame& frame, const Resou - WebsitePoliciesData::applyToDocumentLoader(WTFMove(*m_pendingWebsitePolicies), documentLoader); - m_pendingWebsitePolicies = std::nullopt; +@@ -8186,6 +8324,9 @@ Ref WebPage::createDocumentLoader(LocalFrame& frame, const Resou + WebsitePoliciesData::applyToDocumentLoader(WTFMove(*m_internals->pendingWebsitePolicies), documentLoader); + m_internals->pendingWebsitePolicies = std::nullopt; } + } else if (m_pendingFrameNavigationID) { + documentLoader->setNavigationID(*m_pendingFrameNavigationID); @@ -21941,10 +21532,10 @@ index f37c00d9bdbdc7754ce8bd75c1be645617a3e019..9242983dfaccb87fb55e8126a1c903c0 return documentLoader; diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.h b/Source/WebKit/WebProcess/WebPage/WebPage.h -index dfee35656503c64f8f31ab52756aefdeef38b676..bd0d0408d17d0f4c1ff9352866e80c1ce27a19cd 100644 +index 931473cc7600a2600b0c002f8bd8ae823399691c..3955fa4feb65a8f622b4ebecb0edd56489a1a465 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.h +++ b/Source/WebKit/WebProcess/WebPage/WebPage.h -@@ -71,6 +71,7 @@ +@@ -42,6 +42,7 @@ #include #include #include @@ -21952,7 +21543,7 @@ index dfee35656503c64f8f31ab52756aefdeef38b676..bd0d0408d17d0f4c1ff9352866e80c1c #include #include #include -@@ -1178,11 +1179,11 @@ public: +@@ -1265,11 +1266,11 @@ public: void clearSelection(); void restoreSelectionInFocusedEditableElement(); @@ -21964,9 +21555,9 @@ index dfee35656503c64f8f31ab52756aefdeef38b676..bd0d0408d17d0f4c1ff9352866e80c1c -#if ENABLE(DRAG_SUPPORT) && !PLATFORM(GTK) +#if ENABLE(DRAG_SUPPORT) && !PLATFORM(GTK) && !PLATFORM(WPE) void performDragControllerAction(std::optional, DragControllerAction, WebCore::DragData&&, CompletionHandler, WebCore::DragHandlingMethod, bool, unsigned, WebCore::IntRect, WebCore::IntRect, std::optional)>&&); - void performDragOperation(WebCore::DragData&&, SandboxExtension::Handle&&, Vector&&, CompletionHandler&&); + void performDragOperation(WebCore::DragData&&, SandboxExtensionHandle&&, Vector&&, CompletionHandler&&); #endif -@@ -1197,6 +1198,9 @@ public: +@@ -1284,6 +1285,9 @@ public: void didStartDrag(); void dragCancelled(); OptionSet allowedDragSourceActions() const { return m_allowedDragSourceActions; } @@ -21976,8 +21567,8 @@ index dfee35656503c64f8f31ab52756aefdeef38b676..bd0d0408d17d0f4c1ff9352866e80c1c #endif void beginPrinting(WebCore::FrameIdentifier, const PrintInfo&); -@@ -1272,8 +1276,11 @@ public: - void gestureEvent(WebCore::FrameIdentifier, const WebGestureEvent&, CompletionHandler, bool, std::optional)>&&); +@@ -1359,8 +1363,11 @@ public: + void gestureEvent(WebCore::FrameIdentifier, const WebGestureEvent&); #endif -#if PLATFORM(IOS_FAMILY) @@ -21989,23 +21580,24 @@ index dfee35656503c64f8f31ab52756aefdeef38b676..bd0d0408d17d0f4c1ff9352866e80c1c void dynamicViewportSizeUpdate(const DynamicViewportSizeUpdate&); bool scaleWasSetByUIProcess() const { return m_scaleWasSetByUIProcess; } void willStartUserTriggeredZooming(); -@@ -1423,6 +1430,7 @@ public: +@@ -1510,6 +1517,8 @@ public: void connectInspector(const String& targetId, Inspector::FrontendChannel::ConnectionType); void disconnectInspector(const String& targetId); void sendMessageToTargetBackend(const String& targetId, const String& message); + void resumeInspectorIfPausedInNewWindow(); ++ void didAddWebPageToWebProcess(); void insertNewlineInQuotedContent(); -@@ -1940,6 +1948,7 @@ private: - void createProvisionalFrame(ProvisionalFrameCreationParameters&&, WebCore::FrameIdentifier); - void destroyProvisionalFrame(WebCore::FrameIdentifier); - void loadDidCommitInAnotherProcess(WebCore::FrameIdentifier, std::optional); -+ void loadRequestInFrameForInspector(LoadParameters&&, WebCore::FrameIdentifier); +@@ -1920,6 +1929,7 @@ public: + void showContextMenuFromFrame(const WebCore::FrameIdentifier&, const ContextMenuContextData&, const UserData&); + #endif void loadRequest(LoadParameters&&); - [[noreturn]] void loadRequestWaitingForProcessLaunch(LoadParameters&&, URL&&, WebPageProxyIdentifier, bool); - void loadData(LoadParameters&&); -@@ -1981,6 +1990,7 @@ private: ++ void loadRequestInFrameForInspector(LoadParameters&&, WebCore::FrameIdentifier); + + void setTopContentInset(float); + +@@ -2105,6 +2115,7 @@ private: void updatePotentialTapSecurityOrigin(const WebTouchEvent&, bool wasHandled); #elif ENABLE(TOUCH_EVENTS) void touchEvent(const WebTouchEvent&, CompletionHandler, bool)>&&); @@ -22013,29 +21605,19 @@ index dfee35656503c64f8f31ab52756aefdeef38b676..bd0d0408d17d0f4c1ff9352866e80c1c #endif void cancelPointer(WebCore::PointerID, const WebCore::IntPoint&); -@@ -2126,9 +2136,7 @@ private: - void addLayerForFindOverlay(CompletionHandler)>&&); - void removeLayerForFindOverlay(CompletionHandler&&); - --#if USE(COORDINATED_GRAPHICS) - void sendViewportAttributesChanged(const WebCore::ViewportArguments&); --#endif - - void didChangeSelectedIndexForActivePopupMenu(int32_t newIndex); - void setTextForActivePopupMenu(int32_t index); -@@ -2732,6 +2740,7 @@ private: +@@ -2863,6 +2874,7 @@ private: UserActivity m_userActivity; Markable m_pendingNavigationID; + Markable m_pendingFrameNavigationID; - std::optional m_pendingWebsitePolicies; bool m_mainFrameProgressCompleted { false }; + bool m_shouldDispatchFakeMouseMoveEvents { true }; diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in -index fbfdfdff9c550c9becb8ed9243755926450a9566..61d5056d4ef7d079cfdabc6d31c5a31e58cac907 100644 +index 46c172ccd69d88d6dbc5d9cd946cd0e2045c69dd..26b47e43a543100a5d952120091726aae3661357 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in +++ b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in -@@ -53,10 +53,13 @@ messages -> WebPage WantsAsyncDispatchMessage { +@@ -57,10 +57,13 @@ messages -> WebPage WantsAsyncDispatchMessage { MouseEvent(WebCore::FrameIdentifier frameID, WebKit::WebMouseEvent event, std::optional> sandboxExtensions) SetLastKnownMousePosition(WebCore::FrameIdentifier frameID, WebCore::IntPoint eventPoint, WebCore::IntPoint globalPoint); @@ -22050,7 +21632,7 @@ index fbfdfdff9c550c9becb8ed9243755926450a9566..61d5056d4ef7d079cfdabc6d31c5a31e SetOverrideViewportArguments(std::optional arguments) DynamicViewportSizeUpdate(struct WebKit::DynamicViewportSizeUpdate target) -@@ -146,6 +149,7 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType +@@ -152,6 +155,7 @@ messages -> WebPage WantsAsyncDispatchMessage { ConnectInspector(String targetId, Inspector::FrontendChannel::ConnectionType connectionType) DisconnectInspector(String targetId) SendMessageToTargetBackend(String targetId, String message) @@ -22058,7 +21640,7 @@ index fbfdfdff9c550c9becb8ed9243755926450a9566..61d5056d4ef7d079cfdabc6d31c5a31e #if ENABLE(REMOTE_INSPECTOR) SetIndicating(bool indicating); -@@ -156,6 +160,7 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType +@@ -162,6 +166,7 @@ messages -> WebPage WantsAsyncDispatchMessage { #endif #if !ENABLE(IOS_TOUCH_EVENTS) && ENABLE(TOUCH_EVENTS) TouchEvent(WebKit::WebTouchEvent event) -> (std::optional eventType, bool handled) @@ -22066,7 +21648,7 @@ index fbfdfdff9c550c9becb8ed9243755926450a9566..61d5056d4ef7d079cfdabc6d31c5a31e #endif CancelPointer(WebCore::PointerID pointerId, WebCore::IntPoint documentPoint) -@@ -189,6 +194,7 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType +@@ -195,6 +200,7 @@ messages -> WebPage WantsAsyncDispatchMessage { CreateProvisionalFrame(struct WebKit::ProvisionalFrameCreationParameters creationParameters, WebCore::FrameIdentifier frameID) DestroyProvisionalFrame(WebCore::FrameIdentifier frameID); LoadDidCommitInAnotherProcess(WebCore::FrameIdentifier frameID, std::optional layerHostingContextIdentifier) @@ -22074,7 +21656,7 @@ index fbfdfdff9c550c9becb8ed9243755926450a9566..61d5056d4ef7d079cfdabc6d31c5a31e LoadRequestWaitingForProcessLaunch(struct WebKit::LoadParameters loadParameters, URL resourceDirectoryURL, WebKit::WebPageProxyIdentifier pageID, bool checkAssumedReadAccessToResourceURL) LoadData(struct WebKit::LoadParameters loadParameters) LoadSimulatedRequestAndResponse(struct WebKit::LoadParameters loadParameters, WebCore::ResourceResponse simulatedResponse) -@@ -354,10 +360,10 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType +@@ -361,10 +367,10 @@ messages -> WebPage WantsAsyncDispatchMessage { RemoveLayerForFindOverlay() -> () # Drag and drop. @@ -22087,7 +21669,7 @@ index fbfdfdff9c550c9becb8ed9243755926450a9566..61d5056d4ef7d079cfdabc6d31c5a31e PerformDragControllerAction(std::optional frameID, enum:uint8_t WebKit::DragControllerAction action, WebCore::DragData dragData) -> (std::optional dragOperation, enum:uint8_t WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, WebCore::IntRect insertionRect, WebCore::IntRect editableElementRect, struct std::optional remoteUserInputEventData) PerformDragOperation(WebCore::DragData dragData, WebKit::SandboxExtensionHandle sandboxExtensionHandle, Vector sandboxExtensionsForUpload) -> (bool handled) #endif -@@ -367,6 +373,10 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType +@@ -374,6 +380,10 @@ messages -> WebPage WantsAsyncDispatchMessage { DragCancelled() #endif @@ -22099,10 +21681,10 @@ index fbfdfdff9c550c9becb8ed9243755926450a9566..61d5056d4ef7d079cfdabc6d31c5a31e RequestDragStart(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet allowedActionsMask) RequestAdditionalItemsForDragSession(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet allowedActionsMask) diff --git a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm -index 51c574b2a235066fae685d32f10d06b4a5ae824f..6993e6d3e2e886dc97c0614841dd827655253c42 100644 +index 0b583e682f64d0164def139cbd5c34597ce98db5..306263b5b96515100ecd6639b2566977958b0dea 100644 --- a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm +++ b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm -@@ -803,21 +803,37 @@ String WebPage::platformUserAgent(const URL&) const +@@ -798,21 +798,37 @@ String WebPage::platformUserAgent(const URL&) const bool WebPage::hoverSupportedByPrimaryPointingDevice() const { @@ -22191,10 +21773,10 @@ index f17f5d719d892309ed9c7093384945866b5117b9..1dba47bbf0dbd0362548423a74b38034 } diff --git a/Source/WebKit/WebProcess/WebProcess.cpp b/Source/WebKit/WebProcess/WebProcess.cpp -index 095d4e45286cf0c9ffd5fc35c0de32bd0126b53b..4cf1db20e4c51777a443d3109227b7e4155a8145 100644 +index 2aa5f4a4491d2ba9bae275308b3d669d9d0b3dfa..3e09cd6d639634ee368bfd699f5c597af9367707 100644 --- a/Source/WebKit/WebProcess/WebProcess.cpp +++ b/Source/WebKit/WebProcess/WebProcess.cpp -@@ -89,6 +89,7 @@ +@@ -91,6 +91,7 @@ #include "WebsiteData.h" #include "WebsiteDataStoreParameters.h" #include "WebsiteDataType.h" @@ -22202,7 +21784,7 @@ index 095d4e45286cf0c9ffd5fc35c0de32bd0126b53b..4cf1db20e4c51777a443d3109227b7e4 #include #include #include -@@ -367,6 +368,14 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter +@@ -376,6 +377,14 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter { JSC::Options::AllowUnfinalizedAccessScope scope; JSC::Options::allowNonSPTagging() = false; @@ -22217,7 +21799,7 @@ index 095d4e45286cf0c9ffd5fc35c0de32bd0126b53b..4cf1db20e4c51777a443d3109227b7e4 JSC::Options::notifyOptionsChanged(); } -@@ -374,6 +383,8 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter +@@ -383,6 +392,8 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter platformInitializeProcess(parameters); updateCPULimit(); @@ -22226,8 +21808,16 @@ index 095d4e45286cf0c9ffd5fc35c0de32bd0126b53b..4cf1db20e4c51777a443d3109227b7e4 } void WebProcess::initializeConnection(IPC::Connection* connection) +@@ -937,6 +948,7 @@ void WebProcess::createWebPage(PageIdentifier pageID, WebPageCreationParameters& + accessibilityRelayProcessSuspended(false); + } + ASSERT(result.iterator->value); ++ result.iterator->value->didAddWebPageToWebProcess(); + } + + void WebProcess::removeWebPage(PageIdentifier pageID) diff --git a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm -index d694170887445e2eed73340666bc4847aef4f9a6..6ced22d0953a39582285201e0946d68f954644ad 100644 +index 64e9b56bbc644c8ed1583cdbf41878738860292d..fe83a85ccf53ee33f5a6a7461b40078d77928b61 100644 --- a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm @@ -4223,7 +4223,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END @@ -22240,10 +21830,10 @@ index d694170887445e2eed73340666bc4847aef4f9a6..6ced22d0953a39582285201e0946d68f - (void)touch:(WebEvent *)event { diff --git a/Source/WebKitLegacy/mac/WebView/WebView.mm b/Source/WebKitLegacy/mac/WebView/WebView.mm -index 016c97818b87a5205b1eebce2350c2d7bfb02975..4fe0109484f571bf1cfe53afb57bdf69a4fb295c 100644 +index 0a91e3dcd2071893d4a3f0bb42d43f1435c2d04b..be0037d7284f88c2fbd42070da4d6058408db3c4 100644 --- a/Source/WebKitLegacy/mac/WebView/WebView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebView.mm -@@ -3983,7 +3983,7 @@ + (void)_doNotStartObservingNetworkReachability +@@ -3986,7 +3986,7 @@ + (void)_doNotStartObservingNetworkReachability } #endif // PLATFORM(IOS_FAMILY) @@ -22252,7 +21842,7 @@ index 016c97818b87a5205b1eebce2350c2d7bfb02975..4fe0109484f571bf1cfe53afb57bdf69 - (NSArray *)_touchEventRegions { -@@ -4025,7 +4025,7 @@ - (NSArray *)_touchEventRegions +@@ -4028,7 +4028,7 @@ - (NSArray *)_touchEventRegions }).autorelease(); } @@ -22293,10 +21883,10 @@ index 0000000000000000000000000000000000000000..dd6a53e2d57318489b7e49dd7373706d + LIBVPX_LIBRARIES +) diff --git a/Source/cmake/OptionsGTK.cmake b/Source/cmake/OptionsGTK.cmake -index 4785f6f0c833e7fe5f9cefd586364ccebf41ec32..e77686f25ea59b03c68de4178532496d97898d46 100644 +index 22894830f9eb1be8e2fd3d4fc04711aa49eca6a7..e49dcaf62241f53baf3911e2c40f07c96eb9f0db 100644 --- a/Source/cmake/OptionsGTK.cmake +++ b/Source/cmake/OptionsGTK.cmake -@@ -7,6 +7,9 @@ SET_PROJECT_VERSION(2 47 0) +@@ -7,6 +7,9 @@ SET_PROJECT_VERSION(2 47 2) set(USER_AGENT_BRANDING "" CACHE STRING "Branding to add to user agent string") @@ -22317,7 +21907,7 @@ index 4785f6f0c833e7fe5f9cefd586364ccebf41ec32..e77686f25ea59b03c68de4178532496d include(GStreamerDefinitions) include(FindGLibCompileResources) -@@ -64,6 +71,10 @@ WEBKIT_OPTION_DEFINE(USE_SYSTEM_UNIFDEF "Whether to use a system-provided unifde +@@ -69,6 +76,10 @@ WEBKIT_OPTION_DEFINE(USE_SYSTEM_UNIFDEF "Whether to use a system-provided unifde WEBKIT_OPTION_DEPEND(USE_SYSTEM_SYSPROF_CAPTURE USE_SYSPROF_CAPTURE) @@ -22328,7 +21918,7 @@ index 4785f6f0c833e7fe5f9cefd586364ccebf41ec32..e77686f25ea59b03c68de4178532496d SET_AND_EXPOSE_TO_BUILD(ENABLE_DEVELOPER_MODE ${DEVELOPER_MODE}) if (DEVELOPER_MODE) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_API_TESTS PRIVATE ON) -@@ -148,6 +159,20 @@ endif () +@@ -155,6 +166,20 @@ endif () WEBKIT_OPTION_DEPEND(ENABLE_GPU_PROCESS USE_GBM) @@ -22349,22 +21939,8 @@ index 4785f6f0c833e7fe5f9cefd586364ccebf41ec32..e77686f25ea59b03c68de4178532496d include(GStreamerDependencies) # Finalize the value for all options. Do not attempt to use an option before -diff --git a/Source/cmake/OptionsMSVC.cmake b/Source/cmake/OptionsMSVC.cmake -index 5828bf9ef028ea200a73f973937d610a8771f85f..27f9a084eb0eecd67287c14dc4c363d3042cf965 100644 ---- a/Source/cmake/OptionsMSVC.cmake -+++ b/Source/cmake/OptionsMSVC.cmake -@@ -45,6 +45,9 @@ string(REGEX REPLACE "/W3" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) - string(REGEX REPLACE "/W3" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) - WEBKIT_PREPEND_GLOBAL_COMPILER_FLAGS(/W4) - -+# Not apply class-level dllexport and dllimport attributes to inline member functions -+WEBKIT_PREPEND_GLOBAL_COMPILER_FLAGS(/Zc:dllexportInlines-) -+ - # Make sure incremental linking is turned off, as it creates unacceptably long link times. - string(REPLACE "/INCREMENTAL[:A-Z]+" "" CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) - string(REPLACE "/INCREMENTAL[:A-Z]+" "" CMAKE_EXE_LINKER_FLAGS_DEBUG ${CMAKE_EXE_LINKER_FLAGS_DEBUG}) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake -index fc5429ddf2701ba46e4283a40392903b45400d1f..2c3aebacb3b12dad50d70aed66dc3ba25d91ba29 100644 +index c9b3bcd943d9df19f1b240b8b3704d51c5398411..51c1615a4caedc67675d0c6d49db4ef35f0ad403 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -21,6 +21,9 @@ find_package(WebP REQUIRED COMPONENTS demux) @@ -22377,11 +21953,12 @@ index fc5429ddf2701ba46e4283a40392903b45400d1f..2c3aebacb3b12dad50d70aed66dc3ba2 WEBKIT_OPTION_BEGIN() SET_AND_EXPOSE_TO_BUILD(ENABLE_DEVELOPER_MODE ${DEVELOPER_MODE}) -@@ -83,6 +86,28 @@ if (WPE_VERSION VERSION_GREATER_EQUAL 1.13.90) +@@ -84,6 +87,29 @@ if (WPE_VERSION VERSION_GREATER_EQUAL 1.13.90) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PUBLIC ON) endif () +# Playwright begin. ++WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MINIBROWSER PUBLIC ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_PDFJS PUBLIC OFF) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEDIA_RECORDER PRIVATE OFF) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_THUNDER PRIVATE OFF) @@ -22406,8 +21983,8 @@ index fc5429ddf2701ba46e4283a40392903b45400d1f..2c3aebacb3b12dad50d70aed66dc3ba2 # Public options specific to the WPE port. Do not add any options here unless # there is a strong reason we should support changing the value of the option, # and the option is not relevant to other WebKit ports. -@@ -112,6 +137,11 @@ WEBKIT_OPTION_CONFLICT(ENABLE_WPE_PLATFORM ENABLE_WPE_1_1_API) - WEBKIT_OPTION_DEPEND(ENABLE_DOCUMENTATION ENABLE_INTROSPECTION) +@@ -119,6 +145,11 @@ WEBKIT_OPTION_DEPEND(USE_QT6 ENABLE_WPE_PLATFORM) + WEBKIT_OPTION_DEPEND(USE_SKIA_OPENTYPE_SVG USE_SKIA) WEBKIT_OPTION_DEPEND(USE_SYSTEM_SYSPROF_CAPTURE USE_SYSPROF_CAPTURE) +# Playwright begin. @@ -22419,10 +21996,10 @@ index fc5429ddf2701ba46e4283a40392903b45400d1f..2c3aebacb3b12dad50d70aed66dc3ba2 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_BUBBLEWRAP_SANDBOX PUBLIC ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEMORY_SAMPLER PRIVATE ON) diff --git a/Source/cmake/OptionsWin.cmake b/Source/cmake/OptionsWin.cmake -index a09700bfc69078e82e426ea5cd13fd3d8e84d3ec..52055ce7362d4283a333e5a50f73a12c9b2fa5e2 100644 +index 82a672f6ab17b20b1f2ce373cb627905ada281b2..e72eb75475bc09eeb92bd0b8a207e704674ff5a5 100644 --- a/Source/cmake/OptionsWin.cmake +++ b/Source/cmake/OptionsWin.cmake -@@ -71,6 +71,27 @@ find_package(ZLIB 1.2.11 REQUIRED) +@@ -76,6 +76,27 @@ find_package(ZLIB 1.2.11 REQUIRED) find_package(LibPSL 0.20.2 REQUIRED) find_package(WebP REQUIRED COMPONENTS demux) @@ -22450,7 +22027,7 @@ index a09700bfc69078e82e426ea5cd13fd3d8e84d3ec..52055ce7362d4283a333e5a50f73a12c WEBKIT_OPTION_BEGIN() # FIXME: Most of these options should not be public. -@@ -136,6 +157,14 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FTPDIR PRIVATE OFF) +@@ -141,6 +162,14 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FTPDIR PRIVATE OFF) SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_KEYBOARD_INTERACTIONS ON) SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_MOUSE_INTERACTIONS ON) @@ -22466,7 +22043,7 @@ index a09700bfc69078e82e426ea5cd13fd3d8e84d3ec..52055ce7362d4283a333e5a50f73a12c set(USE_ANGLE_EGL ON) diff --git a/Source/cmake/WebKitCompilerFlags.cmake b/Source/cmake/WebKitCompilerFlags.cmake -index c3c683b650cbbbc882aad6d7f2202abe367af7f6..c3447733a57a09089f178f1c7c7763816252e94c 100644 +index 4882f3de3d9cb011a666563f0bc0e142a705518f..d3f674bf78792088a60a631c245a1fa86dca4d53 100644 --- a/Source/cmake/WebKitCompilerFlags.cmake +++ b/Source/cmake/WebKitCompilerFlags.cmake @@ -122,7 +122,7 @@ macro(WEBKIT_ADD_TARGET_CXX_FLAGS _target) @@ -22493,10 +22070,10 @@ index 576835410df6deac60f0158f1d2d1ef1e5f4c78d..9b492cfe5fef8de340a80f2af70a7d68 WEB_PREFERENCES_GENERATED_FILES = \ TestOptionsGeneratedWebKitLegacyKeyMapping.cpp \ diff --git a/Tools/MiniBrowser/gtk/BrowserTab.c b/Tools/MiniBrowser/gtk/BrowserTab.c -index 6e6c4a5abecb12c6b30e90a93c539b9b9ff27e04..851b4b9ef8da2d4277313503734138f73cdba292 100644 +index 6d48c378699e87f55bbd2550d4971a295b831a24..efb0d8e1e0f7db5d4ce81bc58a97e6c4034ff0b3 100644 --- a/Tools/MiniBrowser/gtk/BrowserTab.c +++ b/Tools/MiniBrowser/gtk/BrowserTab.c -@@ -117,19 +117,34 @@ static void isLoadingChanged(WebKitWebView *webView, GParamSpec *paramSpec, Brow +@@ -117,19 +117,38 @@ static void isLoadingChanged(WebKitWebView *webView, GParamSpec *paramSpec, Brow } } @@ -22504,7 +22081,11 @@ index 6e6c4a5abecb12c6b30e90a93c539b9b9ff27e04..851b4b9ef8da2d4277313503734138f7 +{ + if (webkit_response_policy_decision_is_mime_type_supported(responseDecision)) + return TRUE; -+ const gchar* mimeType = webkit_uri_response_get_mime_type(webkit_response_policy_decision_get_response(responseDecision)); ++ WebKitURIResponse* response = webkit_response_policy_decision_get_response(responseDecision); ++ const guint statusCode = webkit_uri_response_get_status_code(response); ++ if (statusCode == 205 || statusCode == 204) ++ return TRUE; ++ const gchar* mimeType = webkit_uri_response_get_mime_type(response); + if (!mimeType || mimeType[0] == '\0') + return FALSE; + // https://bugs.webkit.org/show_bug.cgi?id=277204 / Ubuntu 24.04 / glib 2.76+ or higher @@ -22535,7 +22116,7 @@ index 6e6c4a5abecb12c6b30e90a93c539b9b9ff27e04..851b4b9ef8da2d4277313503734138f7 return TRUE; } -@@ -180,6 +195,11 @@ static void loadChanged(WebKitWebView *webView, WebKitLoadEvent loadEvent, Brows +@@ -180,6 +199,11 @@ static void loadChanged(WebKitWebView *webView, WebKitLoadEvent loadEvent, Brows #endif } @@ -22547,7 +22128,7 @@ index 6e6c4a5abecb12c6b30e90a93c539b9b9ff27e04..851b4b9ef8da2d4277313503734138f7 static GtkWidget *createInfoBarQuestionMessage(const char *title, const char *text) { GtkWidget *dialog = gtk_info_bar_new_with_buttons("No", GTK_RESPONSE_NO, "Yes", GTK_RESPONSE_YES, NULL); -@@ -741,6 +761,7 @@ static void browserTabConstructed(GObject *gObject) +@@ -746,6 +770,7 @@ static void browserTabConstructed(GObject *gObject) g_signal_connect(tab->webView, "notify::is-loading", G_CALLBACK(isLoadingChanged), tab); g_signal_connect(tab->webView, "decide-policy", G_CALLBACK(decidePolicy), tab); g_signal_connect(tab->webView, "load-changed", G_CALLBACK(loadChanged), tab); @@ -22555,7 +22136,7 @@ index 6e6c4a5abecb12c6b30e90a93c539b9b9ff27e04..851b4b9ef8da2d4277313503734138f7 g_signal_connect(tab->webView, "load-failed-with-tls-errors", G_CALLBACK(loadFailedWithTLSerrors), tab); g_signal_connect(tab->webView, "permission-request", G_CALLBACK(decidePermissionRequest), tab); g_signal_connect(tab->webView, "run-color-chooser", G_CALLBACK(runColorChooserCallback), tab); -@@ -793,6 +814,9 @@ static char *getInternalURI(const char *uri) +@@ -798,6 +823,9 @@ static char *getInternalURI(const char *uri) if (g_str_has_prefix(uri, "about:") && !g_str_equal(uri, "about:blank")) return g_strconcat(BROWSER_ABOUT_SCHEME, uri + strlen ("about"), NULL); @@ -22877,7 +22458,7 @@ index 8433f5360dc4a5f43b68b67192fb3d9bf5064cf1..9fa8f53e90fe5a32be1c8e7a9daa6404 g_clear_object(&interfaceSettings); diff --git a/Tools/MiniBrowser/wpe/main.cpp b/Tools/MiniBrowser/wpe/main.cpp -index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be432ab3ec 100644 +index f5403031c914d7fedeb4649c4891beb7d681007e..eb1fe97ebb4e55eb1d4443e5f66566471ad9733f 100644 --- a/Tools/MiniBrowser/wpe/main.cpp +++ b/Tools/MiniBrowser/wpe/main.cpp @@ -49,6 +49,9 @@ static gboolean headlessMode; @@ -22890,7 +22471,7 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be static const char* contentFilter; static const char* cookiesFile; static const char* cookiesPolicy; -@@ -125,6 +128,9 @@ static const GOptionEntry commandLineOptions[] = +@@ -127,6 +130,9 @@ static const GOptionEntry commandLineOptions[] = #endif { "size", 's', 0, G_OPTION_ARG_CALLBACK, reinterpret_cast(parseWindowSize), "Specify the window size to use, e.g. --size=\"800x600\"", nullptr }, { "version", 'v', 0, G_OPTION_ARG_NONE, &printVersion, "Print the WPE version", nullptr }, @@ -22900,7 +22481,7 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, nullptr, "[URL]" }, { nullptr, 0, 0, G_OPTION_ARG_NONE, nullptr, nullptr, nullptr } }; -@@ -283,15 +289,38 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul +@@ -285,15 +291,38 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul g_main_loop_quit(data->mainLoop); } @@ -22941,7 +22522,7 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be { auto backend = createViewBackend(defaultWindowWidthLegacyAPI, defaultWindowHeightLegacyAPI); WebKitWebViewBackend* viewBackend = nullptr; -@@ -306,12 +335,27 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi +@@ -308,12 +337,27 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi }, backend.release()); } @@ -22975,7 +22556,7 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be #if ENABLE_WPE_PLATFORM if (auto* wpeView = webkit_web_view_get_wpe_view(newWebView)) { -@@ -326,6 +370,10 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi +@@ -328,6 +372,10 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi g_hash_table_add(openViews, newWebView); @@ -22986,9 +22567,9 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be return newWebView; } -@@ -395,13 +443,101 @@ static WebKitFeature* findFeature(WebKitFeatureList* featureList, const char* id - return nullptr; +@@ -415,13 +463,105 @@ void loadConfigFile(WPESettings* settings) } + #endif +static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationAction*, gpointer user_data) +{ @@ -22999,7 +22580,11 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be +{ + if (webkit_response_policy_decision_is_mime_type_supported(responseDecision)) + return true; -+ const gchar* mimeType = webkit_uri_response_get_mime_type(webkit_response_policy_decision_get_response(responseDecision)); ++ auto response = webkit_response_policy_decision_get_response(responseDecision); ++ const auto statusCode = webkit_uri_response_get_status_code(response); ++ if (statusCode == 205 || statusCode == 204) ++ return true; ++ const gchar* mimeType = webkit_uri_response_get_mime_type(response); + if (!mimeType || mimeType[0] == '\0') + return false; + // https://bugs.webkit.org/show_bug.cgi?id=277204 / Ubuntu 24.04 / glib 2.76+ or higher @@ -23089,7 +22674,7 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be webkit_network_session_set_itp_enabled(networkSession, enableITP); if (proxy) { -@@ -428,10 +564,18 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* +@@ -448,10 +588,18 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesFile, storageType); } } @@ -23110,7 +22695,7 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be webkit_website_data_manager_set_itp_enabled(manager, enableITP); if (proxy) { -@@ -462,6 +606,7 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* +@@ -482,6 +630,7 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* } #endif @@ -23118,7 +22703,7 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be WebKitUserContentManager* userContentManager = nullptr; if (contentFilter) { GFile* contentFilterFile = g_file_new_for_commandline_arg(contentFilter); -@@ -540,6 +685,15 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* +@@ -560,6 +709,15 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* "autoplay", WEBKIT_AUTOPLAY_ALLOW, nullptr); @@ -23134,7 +22719,7 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be auto* webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, "backend", viewBackend, "web-context", webContext, -@@ -584,8 +738,6 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* +@@ -606,8 +764,6 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* } #endif @@ -23143,7 +22728,7 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be g_signal_connect(webContext, "automation-started", G_CALLBACK(automationStartedCallback), webView); g_signal_connect(webView, "permission-request", G_CALLBACK(decidePermissionRequest), nullptr); g_signal_connect(webView, "create", G_CALLBACK(createWebView), application); -@@ -597,16 +749,11 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* +@@ -619,16 +775,11 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* webkit_web_view_set_background_color(webView, &color); if (uriArguments) { @@ -23165,7 +22750,7 @@ index f94a8a96c313860ef01de37108acc7c462d13795..f95494c1923c6a3fff562a4da73fa4be webkit_web_view_load_uri(webView, "https://wpewebkit.org"); g_object_unref(webContext); -@@ -702,8 +849,14 @@ int main(int argc, char *argv[]) +@@ -725,8 +876,14 @@ int main(int argc, char *argv[]) } } @@ -23205,43 +22790,6 @@ index 470dcf1f4440f3db350fc416150a2e792a2777c7..31cbc0d22e63d054cf6edcc220a1c6b4 # WebInspectorUI must come after JavaScriptCore and WebCore but before WebKit and WebKit2 my $webKitIndex = first { $projects[$_] eq "Source/WebKitLegacy" } 0..$#projects; -diff --git a/Tools/Scripts/generate-bundle b/Tools/Scripts/generate-bundle -index 297e7d7b3d0889235e621f5c48c1f1480d9685ce..7a7eab25ec0f14ed53f8e688ec9916f2eb7b584e 100755 ---- a/Tools/Scripts/generate-bundle -+++ b/Tools/Scripts/generate-bundle -@@ -677,8 +677,6 @@ class BundleCreator(object): - # bunddle WebKit libraries - objects_to_copy.extend(self._get_webkit_binaries()) - objects_to_copy.append(self._get_webkit_lib('InjectedBundle')) -- if self._platform == 'wpe': -- objects_to_copy.append(self._get_webkit_lib('InspectorResources')) - # Bundle extra system related libraries - gio_modules = self._get_gio_modules() - objects_to_copy.extend(gio_modules) -@@ -766,6 +764,9 @@ class BundleCreator(object): - if needs_to_create_wpe_backend_symlink: - self._ensure_wpe_backend_symlink() - -+ if self._platform == 'wpe': -+ self._bundler.copy(os.path.join(self._buildpath, 'WebInspectorUI', 'DerivedSources', 'inspector.gresource')) -+ - # Now copy data files to share dir (only needed when bunding all for MiniBrowser). - # We assume that the system uses standard paths at /usr/share and /etc for this resources - # Every path should be checked and if some one is not found, then it will raise an error. -diff --git a/Tools/Scripts/webkitpy/binary_bundling/bundle.py b/Tools/Scripts/webkitpy/binary_bundling/bundle.py -index 2d0faab03b2376f3edd20bb2c727ed425ef1aec5..e315434a61800d102e2bac75ac651c3f9e77d3e7 100644 ---- a/Tools/Scripts/webkitpy/binary_bundling/bundle.py -+++ b/Tools/Scripts/webkitpy/binary_bundling/bundle.py -@@ -49,6 +49,9 @@ class BinaryBundler: - def set_use_sys_lib_directory(self, should_use_sys_lib_directory): - self._should_use_sys_lib_directory = should_use_sys_lib_directory - -+ def copy(self, orig_file): -+ shutil.copy(orig_file, self._destination_dir) -+ - def copy_and_maybe_strip_patchelf(self, orig_file, type='bin', strip=True, patchelf_removerpath=True, patchelf_nodefaultlib=False, patchelf_setinterpreter_relativepath=None, object_final_destination_dir=None): - """ This does the following: - 1. Copies the binary/lib (object) diff --git a/Tools/WebKitTestRunner/CMakeLists.txt b/Tools/WebKitTestRunner/CMakeLists.txt index 9e53f459e444b9c10fc5248f0e8059df6c1e0041..c17c875a7dd3ca05c4489578ab32378bca45a7c9 100644 --- a/Tools/WebKitTestRunner/CMakeLists.txt @@ -23258,10 +22806,10 @@ index 9e53f459e444b9c10fc5248f0e8059df6c1e0041..c17c875a7dd3ca05c4489578ab32378b "${WebKitTestRunner_DIR}/InjectedBundle/Bindings/AccessibilityController.idl" "${WebKitTestRunner_DIR}/InjectedBundle/Bindings/AccessibilityTextMarker.idl" diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp -index c1212470ee2e66c2113958894fce3245bbedda5a..1a4ae8ce2386e07267445dbca6f46b5d4a7d26ac 100644 +index a6dc6170c6cb9a6a21fc9abb11b90e3ca1ac3ebc..960d9432d52d5cabe75aca2bc036de248a149681 100644 --- a/Tools/WebKitTestRunner/TestController.cpp +++ b/Tools/WebKitTestRunner/TestController.cpp -@@ -983,6 +983,7 @@ void TestController::createWebViewWithOptions(const TestOptions& options) +@@ -984,6 +984,7 @@ void TestController::createWebViewWithOptions(const TestOptions& options) 0, // requestStorageAccessConfirm shouldAllowDeviceOrientationAndMotionAccess, runWebAuthenticationPanel, @@ -23325,128 +22873,33 @@ index c1381b06b378a5121be926b1dfda3e5509bcd051..773e5882b6f2269201ca49433d0b6986 + + } // namespace WTR -diff --git a/Tools/glib/dependencies/apt b/Tools/glib/dependencies/apt -index 65f8c1ff14a68b7961328fcc284a837c92d4f205..a2731ce34b12b0de7b476a69f906244390cf0cce 100644 ---- a/Tools/glib/dependencies/apt -+++ b/Tools/glib/dependencies/apt -@@ -68,6 +68,7 @@ PACKAGES=( - libwebp-dev - libwoff-dev - libxml2-utils -+ libxcb-glx0-dev - libxslt1-dev - mesa-common-dev - ninja-build diff --git a/Tools/jhbuild/jhbuild-minimal.modules b/Tools/jhbuild/jhbuild-minimal.modules -index 9b006a3700330c89bfbb14906acb5cbaa160b8b2..74d34b7f90ac6bd444cf444e6911d53418aec901 100644 +index 3a0b7425900b14ce2aa0d48aa914cd69bff1f332..22fb1ab2ea76e1e253c79ba1fa3fa448f7584b43 100644 --- a/Tools/jhbuild/jhbuild-minimal.modules +++ b/Tools/jhbuild/jhbuild-minimal.modules -@@ -10,6 +10,7 @@ - - - -+ - - - -@@ -28,11 +29,11 @@ - - - -+ - - - - -- - - - -@@ -40,40 +41,22 @@ - - - -+ -+ -+ -+ - -+ -+ - -- - -- -- -- -- -- -- -- -- -- -- -- -- -- - - - -@@ -117,6 +100,32 @@ +@@ -67,8 +67,8 @@ + + ++ version="1.16.0" ++ hash="sha256:c7f3a3c6b3d006790d486dc7cceda2b6d2e329de07f33bc47dfc53f00f334b2a"/> + + + +@@ -77,8 +77,8 @@ + + ++ version="1.14.3" ++ hash="sha256:10121842595a850291db3e82f3db0b9984df079022d386ce42c2b8508159dc6c"> - - -+ -+ -+ -+ -+ -+ libaom.pc -+ -+ -+ -+ -+ libavif.pc -+ -+ -+ -+ -+ -+ -+ - - - libdrm.pc -@@ -128,7 +137,6 @@ + + +@@ -186,7 +186,6 @@ @@ -23455,10 +22908,10 @@ index 9b006a3700330c89bfbb14906acb5cbaa160b8b2..74d34b7f90ac6bd444cf444e6911d534 diff --git a/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp b/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp -index 05b0196555fbc993ebff3088c1f5926c4cfe391a..dd82d6c324f158045372fb48552fa919d3f50b4f 100644 +index df22308266c6f69d24a60905f8d05e4e80f21b9b..2d0838070dc10793418cbb648b095a5ffa76f1b8 100644 --- a/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp +++ b/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp -@@ -180,32 +180,30 @@ void HeadlessViewBackend::updateSnapshot(PlatformBuffer exportedBuffer) +@@ -210,32 +210,30 @@ void HeadlessViewBackend::updateSnapshot(PlatformBuffer exportedBuffer) return; } @@ -23507,7 +22960,7 @@ index 05b0196555fbc993ebff3088c1f5926c4cfe391a..dd82d6c324f158045372fb48552fa919 wl_shm_buffer_end_access(shmBuffer); } -@@ -214,7 +212,7 @@ void HeadlessViewBackend::updateSnapshot(PlatformBuffer exportedBuffer) +@@ -244,7 +242,7 @@ void HeadlessViewBackend::updateSnapshot(PlatformBuffer exportedBuffer) cairo_surface_destroy(m_snapshot); m_snapshot = cairo_image_surface_create_for_data(buffer, CAIRO_FORMAT_ARGB32, diff --git a/browser_patches/winldd/BUILD_NUMBER b/browser_patches/winldd/BUILD_NUMBER index 9540e56f97ca2..fb35a14c02716 100644 --- a/browser_patches/winldd/BUILD_NUMBER +++ b/browser_patches/winldd/BUILD_NUMBER @@ -1 +1 @@ -1006 +1007 diff --git a/browser_patches/winldd/EXPECTED_BUILDS b/browser_patches/winldd/EXPECTED_BUILDS index cdead62b4c141..349b4249b6a6d 100644 --- a/browser_patches/winldd/EXPECTED_BUILDS +++ b/browser_patches/winldd/EXPECTED_BUILDS @@ -1 +1,2 @@ winldd-win64.zip +winldd-win64.tar.br diff --git a/browser_patches/winldd/buildwin.bat b/browser_patches/winldd/buildwin.bat index 51e2f839da46f..b20447214aac1 100644 --- a/browser_patches/winldd/buildwin.bat +++ b/browser_patches/winldd/buildwin.bat @@ -1,3 +1,5 @@ SET /p BUILD_NUMBER= + +Whether to throw on response codes other than 2xx and 3xx. By default response object is returned +for all status codes. + ### option: APIRequest.newContext.httpCredentials = %%-context-option-httpcredentials-%% * since: v1.16 diff --git a/docs/src/api/class-apirequestcontext.md b/docs/src/api/class-apirequestcontext.md index 40742e2a1fdf4..c96e01991ca2c 100644 --- a/docs/src/api/class-apirequestcontext.md +++ b/docs/src/api/class-apirequestcontext.md @@ -890,3 +890,9 @@ Returns storage state for this request context, contains current cookies and loc ### option: APIRequestContext.storageState.path = %%-storagestate-option-path-%% * since: v1.16 + +### option: APIRequestContext.storageState.indexedDB +* since: v1.51 +- `indexedDB` ? + +Set to `true` to include IndexedDB in the storage state snapshot. diff --git a/docs/src/api/class-browsercontext.md b/docs/src/api/class-browsercontext.md index 85cbc4f62abaa..311b786dab895 100644 --- a/docs/src/api/class-browsercontext.md +++ b/docs/src/api/class-browsercontext.md @@ -1512,7 +1512,7 @@ Whether to emulate network being offline for the browser context. - `name` <[string]> - `value` <[string]> -Returns storage state for this browser context, contains current cookies and local storage snapshot. +Returns storage state for this browser context, contains current cookies, local storage snapshot and IndexedDB snapshot. ## async method: BrowserContext.storageState * since: v1.8 @@ -1522,6 +1522,17 @@ Returns storage state for this browser context, contains current cookies and loc ### option: BrowserContext.storageState.path = %%-storagestate-option-path-%% * since: v1.8 +### option: BrowserContext.storageState.indexedDB +* since: v1.51 +- `indexedDB` ? + +Set to `true` to include [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) in the storage state snapshot. +If your application uses IndexedDB to store authentication tokens, like Firebase Authentication, enable this. + +:::note +IndexedDBs with typed arrays are currently not supported. +::: + ## property: BrowserContext.tracing * since: v1.12 - type: <[Tracing]> diff --git a/docs/src/api/class-browsertype.md b/docs/src/api/class-browsertype.md index 0d41bb1aa7a03..29c323f0025f8 100644 --- a/docs/src/api/class-browsertype.md +++ b/docs/src/api/class-browsertype.md @@ -89,13 +89,17 @@ class BrowserTypeExamples * since: v1.8 - returns: <[Browser]> -This method attaches Playwright to an existing browser instance. When connecting to another browser launched via `BrowserType.launchServer` in Node.js, the major and minor version needs to match the client version (1.2.3 → is compatible with 1.2.x). +This method attaches Playwright to an existing browser instance created via `BrowserType.launchServer` in Node.js. + +:::note +The major and minor version of the Playwright instance that connects needs to match the version of Playwright that launches the browser (1.2.3 → is compatible with 1.2.x). +::: ### param: BrowserType.connect.wsEndpoint * since: v1.10 - `wsEndpoint` <[string]> -A browser websocket endpoint to connect to. +A Playwright browser websocket endpoint to connect to. You obtain this endpoint via `BrowserServer.wsEndpoint`. ### option: BrowserType.connect.headers * since: v1.11 @@ -152,6 +156,10 @@ The default browser context is accessible via [`method: Browser.contexts`]. Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers. ::: +:::note +This connection is significantly lower fidelity than the Playwright protocol connection via [`method: BrowserType.connect`]. If you are experiencing issues or attempting to use advanced functionality, you probably want to use [`method: BrowserType.connect`]. +::: + **Usage** ```js diff --git a/docs/src/api/class-locator.md b/docs/src/api/class-locator.md index 41ee8aab4fdc9..42c09c79f19a8 100644 --- a/docs/src/api/class-locator.md +++ b/docs/src/api/class-locator.md @@ -155,7 +155,7 @@ Additional locator to match. - returns: <[string]> Captures the aria snapshot of the given element. -Read more about [aria snapshots](../aria-snapshots.md) and [`method: LocatorAssertions.toMatchAriaSnapshot#1`] for the corresponding assertion. +Read more about [aria snapshots](../aria-snapshots.md) and [`method: LocatorAssertions.toMatchAriaSnapshot`] for the corresponding assertion. **Usage** @@ -864,31 +864,6 @@ If [`param: expression`] throws or rejects, this method throws. **Usage** -```js -const tweets = page.locator('.tweet .retweets'); -expect(await tweets.evaluate(node => node.innerText)).toBe('10 retweets'); -``` - -```java -Locator tweets = page.locator(".tweet .retweets"); -assertEquals("10 retweets", tweets.evaluate("node => node.innerText")); -``` - -```python async -tweets = page.locator(".tweet .retweets") -assert await tweets.evaluate("node => node.innerText") == "10 retweets" -``` - -```python sync -tweets = page.locator(".tweet .retweets") -assert tweets.evaluate("node => node.innerText") == "10 retweets" -``` - -```csharp -var tweets = page.Locator(".tweet .retweets"); -Assert.AreEqual("10 retweets", await tweets.EvaluateAsync("node => node.innerText")); -``` - ### param: Locator.evaluate.expression = %%-evaluate-expression-%% * since: v1.14 @@ -1115,6 +1090,9 @@ await rowLocator ### option: Locator.filter.hasNotText = %%-locator-option-has-not-text-%% * since: v1.33 +### option: Locator.filter.visible = %%-locator-option-visible-%% +* since: v1.51 + ## method: Locator.first * since: v1.14 - returns: <[Locator]> @@ -2060,9 +2038,9 @@ Triggers a `change` and `input` event once all the provided options have been se ```html ``` @@ -2357,7 +2335,7 @@ This method expects [Locator] to point to an ## async method: Locator.tap * since: v1.14 -Perform a tap gesture on the element matching the locator. +Perform a tap gesture on the element matching the locator. For examples of emulating other gestures by manually dispatching touch events, see the [emulating legacy touch events](../touch-events.md) page. **Details** diff --git a/docs/src/api/class-locatorassertions.md b/docs/src/api/class-locatorassertions.md index 63b487208f491..59618d0fbfd93 100644 --- a/docs/src/api/class-locatorassertions.md +++ b/docs/src/api/class-locatorassertions.md @@ -240,6 +240,24 @@ Expected accessible description. ### option: LocatorAssertions.NotToHaveAccessibleDescription.timeout = %%-csharp-java-python-assertions-timeout-%% * since: v1.44 +## async method: LocatorAssertions.NotToHaveAccessibleErrorMessage +* since: v1.50 +* langs: python + +The opposite of [`method: LocatorAssertions.toHaveAccessibleErrorMessage`]. + +### param: LocatorAssertions.NotToHaveAccessibleErrorMessage.errorMessage +* since: v1.50 +- `errorMessage` <[string]|[RegExp]> + +Expected accessible error message. + +### option: LocatorAssertions.NotToHaveAccessibleErrorMessage.ignoreCase = %%-assertions-ignore-case-%% +* since: v1.50 + +### option: LocatorAssertions.NotToHaveAccessibleErrorMessage.timeout = %%-csharp-java-python-assertions-timeout-%% +* since: v1.50 + ## async method: LocatorAssertions.NotToHaveAccessibleName * since: v1.44 @@ -446,7 +464,7 @@ Expected options currently selected. * since: v1.49 * langs: python -The opposite of [`method: LocatorAssertions.toMatchAriaSnapshot#1`]. +The opposite of [`method: LocatorAssertions.toMatchAriaSnapshot`]. ### param: LocatorAssertions.NotToMatchAriaSnapshot.expected * since: v1.49 @@ -2180,7 +2198,7 @@ Expected options currently selected. * since: v1.23 -## async method: LocatorAssertions.toMatchAriaSnapshot#1 +## async method: LocatorAssertions.toMatchAriaSnapshot * since: v1.49 * langs: - alias-java: matchesAriaSnapshot @@ -2229,14 +2247,14 @@ assertThat(page.locator("body")).matchesAriaSnapshot(""" """); ``` -### param: LocatorAssertions.toMatchAriaSnapshot#1.expected +### param: LocatorAssertions.toMatchAriaSnapshot.expected * since: v1.49 - `expected` -### option: LocatorAssertions.toMatchAriaSnapshot#1.timeout = %%-js-assertions-timeout-%% +### option: LocatorAssertions.toMatchAriaSnapshot.timeout = %%-js-assertions-timeout-%% * since: v1.49 -### option: LocatorAssertions.toMatchAriaSnapshot#1.timeout = %%-csharp-java-python-assertions-timeout-%% +### option: LocatorAssertions.toMatchAriaSnapshot.timeout = %%-csharp-java-python-assertions-timeout-%% * since: v1.49 ## async method: LocatorAssertions.toMatchAriaSnapshot#2 @@ -2245,28 +2263,13 @@ assertThat(page.locator("body")).matchesAriaSnapshot(""" Asserts that the target element matches the given [accessibility snapshot](../aria-snapshots.md). +Snapshot is stored in a separate `.aria.yml` file in a location configured by `expect.toMatchAriaSnapshot.pathTemplate` and/or `snapshotPathTemplate` properties in the configuration file. + **Usage** ```js await expect(page.locator('body')).toMatchAriaSnapshot(); -await expect(page.locator('body')).toMatchAriaSnapshot({ name: 'snapshot' }); -await expect(page.locator('body')).toMatchAriaSnapshot({ path: '/path/to/snapshot.yml' }); -``` - -```python async -await expect(page.locator('body')).to_match_aria_snapshot(path='/path/to/snapshot.yml') -``` - -```python sync -expect(page.locator('body')).to_match_aria_snapshot(path='/path/to/snapshot.yml') -``` - -```csharp -await Expect(page.Locator("body")).ToMatchAriaSnapshotAsync(new { Path = "/path/to/snapshot.yml" }); -``` - -```java -assertThat(page.locator("body")).matchesAriaSnapshot(new LocatorAssertions.MatchesAriaSnapshotOptions().setPath("/path/to/snapshot.yml")); +await expect(page.locator('body')).toMatchAriaSnapshot({ name: 'body.aria.yml' }); ``` ### option: LocatorAssertions.toMatchAriaSnapshot#2.name @@ -2274,13 +2277,8 @@ assertThat(page.locator("body")).matchesAriaSnapshot(new LocatorAssertions.Match * langs: js - `name` <[string]> -Name of the snapshot to store in the snapshot folder corresponding to this test. Generates ordinal name if not specified. - -### option: LocatorAssertions.toMatchAriaSnapshot#2.path -* since: v1.50 -- `path` <[string]> - -Path to the YAML snapshot file. +Name of the snapshot to store in the snapshot folder corresponding to this test. +Generates sequential names if not specified. ### option: LocatorAssertions.toMatchAriaSnapshot#2.timeout = %%-js-assertions-timeout-%% * since: v1.50 diff --git a/docs/src/api/class-page.md b/docs/src/api/class-page.md index ec58c027b34f3..b59f2cb3fe59f 100644 --- a/docs/src/api/class-page.md +++ b/docs/src/api/class-page.md @@ -1309,6 +1309,18 @@ Emulates `'forced-colors'` media feature, supported values are `'active'` and `' * langs: csharp, python - `forcedColors` <[ForcedColors]<"active"|"none"|"null">> +### option: Page.emulateMedia.contrast +* since: v1.51 +* langs: js, java +- `contrast` > + +Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. Passing `null` disables contrast emulation. + +### option: Page.emulateMedia.contrast +* since: v1.51 +* langs: csharp, python +- `contrast` <[Contrast]<"no-preference"|"more"|"null">> + ## async method: Page.evalOnSelector * since: v1.9 * discouraged: This method does not wait for the element to pass actionability diff --git a/docs/src/api/class-pageassertions.md b/docs/src/api/class-pageassertions.md index 8eefd41f023aa..6420735f2be59 100644 --- a/docs/src/api/class-pageassertions.md +++ b/docs/src/api/class-pageassertions.md @@ -296,7 +296,18 @@ Ensures the page is navigated to the given URL. **Usage** ```js -await expect(page).toHaveURL(/.*checkout/); +// Check for the page URL to be 'https://playwright.dev/docs/intro' (including query string) +await expect(page).toHaveURL('https://playwright.dev/docs/intro'); + +// Check for the page URL to contain 'doc', followed by an optional 's', followed by '/' +await expect(page).toHaveURL(/docs?\//); + +// Check for the predicate to be satisfied +// For example: verify query strings +await expect(page).toHaveURL(url => { + const params = url.searchParams; + return params.has('search') && params.has('options') && params.get('id') === '5'; +}); ``` ```java @@ -323,8 +334,17 @@ expect(page).to_have_url(re.compile(".*checkout")) await Expect(Page).ToHaveURLAsync(new Regex(".*checkout")); ``` +### param: PageAssertions.toHaveURL.url +* since: v1.18 +* langs: js +- `url` <[string]|[RegExp]|[function]\([URL]\):[boolean]> + +Expected URL string, RegExp, or predicate receiving [URL] to match. +When [`option: Browser.newContext.baseURL`] is provided via the context options and the `url` argument is a string, the two values are merged via the [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor and used for the comparison against the current browser URL. + ### param: PageAssertions.toHaveURL.urlOrRegExp * since: v1.18 +* langs: csharp, python, java - `urlOrRegExp` <[string]|[RegExp]> Expected URL string or RegExp. @@ -333,7 +353,7 @@ Expected URL string or RegExp. * since: v1.44 - `ignoreCase` <[boolean]> -Whether to perform case-insensitive match. [`option: ignoreCase`] option takes precedence over the corresponding regular expression flag if specified. +Whether to perform case-insensitive match. [`option: ignoreCase`] option takes precedence over the corresponding regular expression parameter if specified. A provided predicate ignores this flag. ### option: PageAssertions.toHaveURL.timeout = %%-js-assertions-timeout-%% * since: v1.18 diff --git a/docs/src/api/class-touchscreen.md b/docs/src/api/class-touchscreen.md index bd6e1ed9f095a..d7871addd7a00 100644 --- a/docs/src/api/class-touchscreen.md +++ b/docs/src/api/class-touchscreen.md @@ -4,6 +4,8 @@ The Touchscreen class operates in main-frame CSS pixels relative to the top-left corner of the viewport. Methods on the touchscreen can only be used in browser contexts that have been initialized with `hasTouch` set to true. +This class is limited to emulating tap gestures. For examples of other gestures simulated by manually dispatching touch events, see the [emulating legacy touch events](../touch-events.md) page. + ## async method: Touchscreen.tap * since: v1.8 diff --git a/docs/src/api/class-websocket.md b/docs/src/api/class-websocket.md index 3b3308b885666..e33740eacaad6 100644 --- a/docs/src/api/class-websocket.md +++ b/docs/src/api/class-websocket.md @@ -1,7 +1,9 @@ # class: WebSocket * since: v1.8 -The [WebSocket] class represents websocket connections in the page. +The [WebSocket] class represents WebSocket connections within a page. It provides the ability to inspect and manipulate the data being transmitted and received. + +If you want to intercept or modify WebSocket frames, consider using [WebSocketRoute]. ## event: WebSocket.close * since: v1.8 diff --git a/docs/src/api/params.md b/docs/src/api/params.md index a1f909a4fb672..fd548c9c41a04 100644 --- a/docs/src/api/params.md +++ b/docs/src/api/params.md @@ -259,9 +259,9 @@ Specify environment variables that will be visible to the browser. Defaults to ` - `httpOnly` <[boolean]> - `secure` <[boolean]> - `sameSite` <[SameSiteAttribute]<"Strict"|"Lax"|"None">> sameSite flag - - `origins` <[Array]<[Object]>> localStorage to set for context + - `origins` <[Array]<[Object]>> - `origin` <[string]> - - `localStorage` <[Array]<[Object]>> + - `localStorage` <[Array]<[Object]>> localStorage to set for context - `name` <[string]> - `value` <[string]> @@ -673,6 +673,18 @@ Emulates `'forced-colors'` media feature, supported values are `'active'`, `'non Emulates `'forced-colors'` media feature, supported values are `'active'`, `'none'`. See [`method: Page.emulateMedia`] for more details. Passing `'null'` resets emulation to system defaults. Defaults to `'none'`. +## context-option-contrast +* langs: js, java +- `contrast` > + +Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. See [`method: Page.emulateMedia`] for more details. Passing `null` resets emulation to system defaults. Defaults to `'no-preference'`. + +## context-option-contrast-csharp-python +* langs: csharp, python +- `contrast` <[Contrast]<"no-preference"|"more"|"null">> + +Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. See [`method: Page.emulateMedia`] for more details. Passing `'null'` resets emulation to system defaults. Defaults to `'no-preference'`. + ## context-option-logger * langs: js - `logger` <[Logger]> @@ -973,6 +985,8 @@ between the same pixel in compared images, between zero (strict) and one (lax), - %%-context-option-reducedMotion-csharp-python-%% - %%-context-option-forcedColors-%% - %%-context-option-forcedColors-csharp-python-%% +- %%-context-option-contrast-%% +- %%-context-option-contrast-csharp-python-%% - %%-context-option-logger-%% - %%-context-option-videospath-%% - %%-context-option-videosize-%% @@ -1140,6 +1154,11 @@ Note that outer and inner locators must belong to the same frame. Inner locator Matches elements that do not contain specified text somewhere inside, possibly in a child or a descendant element. When passed a [string], matching is case-insensitive and searches for a substring. +## locator-option-visible +- `visible` <[boolean]> + +Only matches visible or invisible elements. + ## locator-options-list-v1.14 - %%-locator-option-has-text-%% - %%-locator-option-has-%% @@ -1190,6 +1209,7 @@ Specify screenshot type, defaults to `png`. Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink box `#FF00FF` (customized by [`option: maskColor`]) that completely covers its bounding box. +The mask is also applied to invisible elements, see [Matching only visible elements](../locators.md#matching-only-visible-elements) to disable that. ## screenshot-option-mask-color * since: v1.35 @@ -1758,7 +1778,9 @@ await Expect(Page.GetByTitle("Issues count")).toHaveText("25 issues"); - `type` ?<[string]> * langs: js -This option configures a template controlling location of snapshots generated by [`method: PageAssertions.toHaveScreenshot#1`] and [`method: SnapshotAssertions.toMatchSnapshot#1`]. +This option configures a template controlling location of snapshots generated by [`method: PageAssertions.toHaveScreenshot#1`], [`method: LocatorAssertions.toMatchAriaSnapshot#2`] and [`method: SnapshotAssertions.toMatchSnapshot#1`]. + +You can configure templates for each assertion separately in [`property: TestConfig.expect`]. **Usage** @@ -1767,7 +1789,19 @@ import { defineConfig } from '@playwright/test'; export default defineConfig({ testDir: './tests', + + // Single template for all assertions snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}', + + // Assertion-specific templates + expect: { + toHaveScreenshot: { + pathTemplate: '{testDir}/__screenshots__{/projectName}/{testFilePath}/{arg}{ext}', + }, + toMatchAriaSnapshot: { + pathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}', + }, + }, }); ``` @@ -1798,22 +1832,22 @@ test.describe('suite', () => { The list of supported tokens: -* `{arg}` - Relative snapshot path **without extension**. These come from the arguments passed to the `toHaveScreenshot()` and `toMatchSnapshot()` calls; if called without arguments, this will be an auto-generated snapshot name. +* `{arg}` - Relative snapshot path **without extension**. This comes from the arguments passed to `toHaveScreenshot()`, `toMatchAriaSnapshot()` or `toMatchSnapshot()`; if called without arguments, this will be an auto-generated snapshot name. * Value: `foo/bar/baz` -* `{ext}` - snapshot extension (with dots) +* `{ext}` - Snapshot extension (with the leading dot). * Value: `.png` * `{platform}` - The value of `process.platform`. * `{projectName}` - Project's file-system-sanitized name, if any. * Value: `''` (empty string). -* `{snapshotDir}` - Project's [`property: TestConfig.snapshotDir`]. +* `{snapshotDir}` - Project's [`property: TestProject.snapshotDir`]. * Value: `/home/playwright/tests` (since `snapshotDir` is not provided in config, it defaults to `testDir`) -* `{testDir}` - Project's [`property: TestConfig.testDir`]. - * Value: `/home/playwright/tests` (absolute path is since `testDir` is resolved relative to directory with config) +* `{testDir}` - Project's [`property: TestProject.testDir`]. + * Value: `/home/playwright/tests` (absolute path since `testDir` is resolved relative to directory with config) * `{testFileDir}` - Directories in relative path from `testDir` to **test file**. * Value: `page` * `{testFileName}` - Test file name with extension. * Value: `page-click.spec.ts` -* `{testFilePath}` - Relative path from `testDir` to **test file** +* `{testFilePath}` - Relative path from `testDir` to **test file**. * Value: `page/page-click.spec.ts` * `{testName}` - File-system-sanitized test title, including parent describes but excluding file name. * Value: `suite-test-should-work` diff --git a/docs/src/aria-snapshots.md b/docs/src/aria-snapshots.md index b52ff826503b1..2bbfd8a654e11 100644 --- a/docs/src/aria-snapshots.md +++ b/docs/src/aria-snapshots.md @@ -6,7 +6,7 @@ import LiteYouTube from '@site/src/components/LiteYouTube'; ## Overview -With the Playwright Snapshot testing you can assert the accessibility tree of a page against a predefined snapshot template. +With Playwright's Snapshot testing you can assert the accessibility tree of a page against a predefined snapshot template. ```js await page.goto('https://playwright.dev/'); @@ -79,12 +79,12 @@ confirms that an input field has the expected value. Assertion tests are specific and generally check the current state of an element or property against an expected, predefined state. They work well for predictable, single-value checks but are limited in scope when testing the -broader structure or variations. +broader structure or variations. **Advantages** - **Clarity**: The intent of the test is explicit and easy to understand. - **Specificity**: Tests focus on particular aspects of functionality, making them more robust - against unrelated changes. + against unrelated changes. - **Debugging**: Failures provide targeted feedback, pointing directly to the problematic aspect. **Disadvantages** @@ -154,7 +154,7 @@ structure of a page, use the [Chrome DevTools Accessibility Pane](https://develo ## Snapshot matching -The [`method: LocatorAssertions.toMatchAriaSnapshot#1`] assertion method in Playwright compares the accessible +The [`method: LocatorAssertions.toMatchAriaSnapshot`] assertion method in Playwright compares the accessible structure of the locator scope with a predefined aria snapshot template, helping validate the page's state against testing requirements. @@ -222,7 +222,7 @@ attributes. ``` In this example, the button role is matched, but the accessible name ("Submit") is not specified, allowing the test to -pass regardless of the button’s label. +pass regardless of the button's label.
@@ -280,12 +280,12 @@ support regex patterns. ## Generating snapshots -Creating aria snapshots in Playwright helps ensure and maintain your application’s structure. +Creating aria snapshots in Playwright helps ensure and maintain your application's structure. You can generate snapshots in various ways depending on your testing setup and workflow. -### 1. Generating snapshots with the Playwright code generator +### Generating snapshots with the Playwright code generator -If you’re using Playwright’s [Code Generator](./codegen.md), generating aria snapshots is streamlined with its +If you're using Playwright's [Code Generator](./codegen.md), generating aria snapshots is streamlined with its interactive interface: - **"Assert snapshot" Action**: In the code generator, you can use the "Assert snapshot" action to automatically create @@ -296,20 +296,18 @@ recorded test flow. aria snapshot for a selected locator, letting you explore, inspect, and verify element roles, attributes, and accessible names to aid snapshot creation and review. -### 2. Updating snapshots with `@playwright/test` and the `--update-snapshots` flag +### Updating snapshots with `@playwright/test` and the `--update-snapshots` flag +* langs: js -When using the Playwright test runner (`@playwright/test`), you can automatically update snapshots by running tests with -the `--update-snapshots` flag: +When using the Playwright test runner (`@playwright/test`), you can automatically update snapshots with the `--update-snapshots` flag, `-u` for short. + +Running tests with the `--update-snapshots` flag will update snapshots that did not match. Matching snapshots will not be updated. ```bash npx playwright test --update-snapshots ``` -This command regenerates snapshots for assertions, including aria snapshots, replacing outdated ones. It’s -useful when application structure changes require new snapshots as a baseline. Note that Playwright will wait for the -maximum expect timeout specified in the test runner configuration to ensure the -page is settled before taking the snapshot. It might be necessary to adjust the `--timeout` if the test hits the timeout -while generating snapshots. +Updating snapshots is useful when application structure changes require new snapshots as a baseline. Note that Playwright will wait for the maximum expect timeout specified in the test runner configuration to ensure the page is settled before taking the snapshot. It might be necessary to adjust the `--timeout` if the test hits the timeout while generating snapshots. #### Empty template for snapshot generation @@ -329,10 +327,40 @@ When updating snapshots, Playwright creates patch files that capture differences applied, and committed to source control, allowing teams to track structural changes over time and ensure updates are consistent with application requirements. -### 3. Using the `Locator.ariaSnapshot` method +The way source code is updated can be changed using the `--update-source-method` flag. There are several options available: + +- **"patch"** (default): Generates a unified diff file that can be applied to the source code using `git apply`. +- **"3way"**: Generates merge conflict markers in your source code, allowing you to choose whether to accept changes. +- **"overwrite"**: Overwrites the source code with the new snapshot values. + +```bash +npx playwright test --update-snapshots --update-source-mode=3way +``` + +#### Snapshots as separate files + +To store your snapshots in a separate file, use the `toMatchAriaSnapshot` method with the `name` option, specifying a `.aria.yml` file extension. + +```js +await expect(page.getByRole('main')).toMatchAriaSnapshot({ name: 'main.aria.yml' }); +``` + +By default, snapshots from a test file `example.spec.ts` are placed in the `example.spec.ts-snapshots` directory. As snapshots should be the same across browsers, only one snapshot is saved even if testing with multiple browsers. Should you wish, you can customize the [snapshot path template](./api/class-testconfig#test-config-snapshot-path-template) using the following configuration: + +```js +export default defineConfig({ + expect: { + toMatchAriaSnapshot: { + pathTemplate: '__snapshots__/{testFilePath}/{arg}{ext}', + }, + }, +}); +``` + +### Using the `Locator.ariaSnapshot` method The [`method: Locator.ariaSnapshot`] method allows you to programmatically create a YAML representation of accessible -elements within a locator’s scope, especially helpful for generating snapshots dynamically during test execution. +elements within a locator's scope, especially helpful for generating snapshots dynamically during test execution. **Example**: @@ -361,7 +389,7 @@ var snapshot = await page.Locator("body").AriaSnapshotAsync(); Console.WriteLine(snapshot); ``` -This command outputs the aria snapshot within the specified locator’s scope in YAML format, which you can validate +This command outputs the aria snapshot within the specified locator's scope in YAML format, which you can validate or store as needed. ## Accessibility tree examples diff --git a/docs/src/auth.md b/docs/src/auth.md index a070d2d39590a..4a3853edf1006 100644 --- a/docs/src/auth.md +++ b/docs/src/auth.md @@ -232,7 +232,7 @@ await page.goto('https://github.com/login') # Interact with login form await page.get_by_label("Username or email address").fill("username") await page.get_by_label("Password").fill("password") -await page.page.get_by_role("button", name="Sign in").click() +await page.get_by_role("button", name="Sign in").click() # Continue with the test ``` @@ -266,9 +266,9 @@ existing authentication state instead. Playwright provides a way to reuse the signed-in state in the tests. That way you can log in only once and then skip the log in step for all of the tests. -Web apps use cookie-based or token-based authentication, where authenticated state is stored as [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) or in [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage). Playwright provides [`method: BrowserContext.storageState`] method that can be used to retrieve storage state from authenticated contexts and then create new contexts with prepopulated state. +Web apps use cookie-based or token-based authentication, where authenticated state is stored as [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), in [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) or in [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API). Playwright provides [`method: BrowserContext.storageState`] method that can be used to retrieve storage state from authenticated contexts and then create new contexts with prepopulated state. -Cookies and local storage state can be used across different browsers. They depend on your application's authentication model: some apps might require both cookies and local storage. +Cookies, local storage and IndexedDB state can be used across different browsers. They depend on your application's authentication model which may require some combination of cookies, local storage or IndexedDB. The following code snippet retrieves state from an authenticated context and creates a new context with that state. @@ -583,7 +583,7 @@ test('admin and user', async ({ adminPage, userPage }) => { ### Session storage -Reusing authenticated state covers [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) and [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) based authentication. Rarely, [session storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage) is used for storing information associated with the signed-in state. Session storage is specific to a particular domain and is not persisted across page loads. Playwright does not provide API to persist session storage, but the following snippet can be used to save/load session storage. +Reusing authenticated state covers [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) and [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) based authentication. Rarely, [session storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage) is used for storing information associated with the signed-in state. Session storage is specific to a particular domain and is not persisted across page loads. Playwright does not provide API to persist session storage, but the following snippet can be used to save/load session storage. ```js // Get session storage and store as env variable diff --git a/docs/src/ci.md b/docs/src/ci.md index 54e0a7a749a14..89ce6242fba0f 100644 --- a/docs/src/ci.md +++ b/docs/src/ci.md @@ -804,7 +804,7 @@ Sharding in CircleCI is indexed with 0 which means that you will need to overrid executor: pw-noble-development parallelism: 4 steps: - - run: SHARD="$((${CIRCLE_NODE_INDEX}+1))"; npx playwright test -- --shard=${SHARD}/${CIRCLE_NODE_TOTAL} + - run: SHARD="$((${CIRCLE_NODE_INDEX}+1))"; npx playwright test --shard=${SHARD}/${CIRCLE_NODE_TOTAL} ``` ### Jenkins diff --git a/docs/src/codegen.md b/docs/src/codegen.md index f0d9a605f584c..641383d7b4e0a 100644 --- a/docs/src/codegen.md +++ b/docs/src/codegen.md @@ -325,7 +325,7 @@ pwsh bin/Debug/netX/playwright.ps1 codegen --timezone="Europe/Rome" --geolocatio ### Preserve authenticated state -Run `codegen` with `--save-storage` to save [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) and [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) at the end of the session. This is useful to separately record an authentication step and reuse it later when recording more tests. +Run `codegen` with `--save-storage` to save [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) and [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) data at the end of the session. This is useful to separately record an authentication step and reuse it later when recording more tests. ```bash js npx playwright codegen github.com/microsoft/playwright --save-storage=auth.json @@ -375,7 +375,7 @@ Make sure you only use the `auth.json` locally as it contains sensitive informat #### Load authenticated state -Run with `--load-storage` to consume the previously loaded storage from the `auth.json`. This way, all [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) and [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) will be restored, bringing most web apps to the authenticated state without the need to login again. This means you can continue generating tests from the logged in state. +Run with `--load-storage` to consume the previously loaded storage from the `auth.json`. This way, all [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) and [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) data will be restored, bringing most web apps to the authenticated state without the need to login again. This means you can continue generating tests from the logged in state. ```bash js npx playwright codegen --load-storage=auth.json github.com/microsoft/playwright diff --git a/docs/src/locators.md b/docs/src/locators.md index c3a2817670caf..b0a1c0e8f5aac 100644 --- a/docs/src/locators.md +++ b/docs/src/locators.md @@ -751,10 +751,10 @@ page.locator("x-details", new Page.LocatorOptions().setHasText("Details")) .click(); ``` ```python async -await page.locator("x-details", has_text="Details" ).click() +await page.locator("x-details", has_text="Details").click() ``` ```python sync -page.locator("x-details", has_text="Details" ).click() +page.locator("x-details", has_text="Details").click() ``` ```csharp await page @@ -1310,19 +1310,19 @@ Consider a page with two buttons, the first invisible and the second [visible](. * This will only find a second button, because it is visible, and then click it. ```js - await page.locator('button').locator('visible=true').click(); + await page.locator('button').filter({ visible: true }).click(); ``` ```java - page.locator("button").locator("visible=true").click(); + page.locator("button").filter(new Locator.FilterOptions.setVisible(true)).click(); ``` ```python async - await page.locator("button").locator("visible=true").click() + await page.locator("button").filter(visible=True).click() ``` ```python sync - page.locator("button").locator("visible=true").click() + page.locator("button").filter(visible=True).click() ``` ```csharp - await page.Locator("button").Locator("visible=true").ClickAsync(); + await page.Locator("button").Filter(new() { Visible = true }).ClickAsync(); ``` ## Lists diff --git a/docs/src/network.md b/docs/src/network.md index fc2471a321ce4..bdb5b71c6ee07 100644 --- a/docs/src/network.md +++ b/docs/src/network.md @@ -708,9 +708,13 @@ Playwright uses simplified glob patterns for URL matching in network interceptio - A double `**` matches any characters including `/` 1. Question mark `?` matches any single character except `/` 1. Curly braces `{}` can be used to match a list of options separated by commas `,` +1. Square brackets `[]` can be used to match a set of characters +1. Backslash `\` can be used to escape any of special characters (note to escape backslash itself as `\\`) Examples: - `https://example.com/*.js` matches `https://example.com/file.js` but not `https://example.com/path/file.js` +- `https://example.com/\\?page=1` matches `https://example.com/?page=1` but not `https://example.com` +- `**/v[0-9]*` matches `https://example.com/v1/` but not `https://example.com/vote/` - `**/*.js` matches both `https://example.com/file.js` and `https://example.com/path/file.js` - `**/*.{png,jpg,jpeg}` matches all image requests diff --git a/docs/src/release-notes-csharp.md b/docs/src/release-notes-csharp.md index dab0fdf34e6b5..e3759f5c0ee72 100644 --- a/docs/src/release-notes-csharp.md +++ b/docs/src/release-notes-csharp.md @@ -4,12 +4,91 @@ title: "Release notes" toc_max_heading_level: 2 --- +## Version 1.51 + +### Highlights + +* New option [`option: BrowserContext.storageState.indexedDB`] for [`method: BrowserContext.storageState`] allows to save and restore IndexedDB contents. Useful when your application uses [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) to store authentication tokens, like Firebase Authentication. + + Here is an example following the [authentication guide](./auth.md#reusing-signed-in-state): + + ```csharp + // Save storage state into the file. Make sure to include IndexedDB. + await context.StorageStateAsync(new() + { + Path = "../../../playwright/.auth/state.json", + IndexedDB = true + }); + + // Create a new context with the saved storage state. + var context = await browser.NewContextAsync(new() + { + StorageStatePath = "../../../playwright/.auth/state.json" + }); + ``` + +* New option [`option: Locator.filter.visible`] for [`method: Locator.filter`] allows matching only visible elements. + + ```csharp + // Ignore invisible todo items. + var todoItems = Page.GetByTestId("todo-item").Filter(new() { Visible = true }); + // Check there are exactly 3 visible ones. + await Expect(todoItems).ToHaveCountAsync(3); + ``` + +* New option `Contrast` for methods [`method: Page.emulateMedia`] and [`method: Browser.newContext`] allows to emulate the `prefers-contrast` media feature. + +* New option [`option: APIRequest.newContext.failOnStatusCode`] makes all fetch requests made through the [APIRequestContext] throw on response codes other than 2xx and 3xx. + +### Browser Versions + +* Chromium 134.0.6998.35 +* Mozilla Firefox 135.0 +* WebKit 18.4 + +This version was also tested against the following stable channels: + +* Google Chrome 133 +* Microsoft Edge 133 + + +## Version 1.50 + +### Support for Xunit + +* Support for xUnit 2.8+ via [Microsoft.Playwright.Xunit](https://www.nuget.org/packages/Microsoft.Playwright.Xunit). Follow our [Getting Started](./intro.md) guide to learn more. + +### Miscellaneous + +* Added method [`method: LocatorAssertions.toHaveAccessibleErrorMessage`] to assert the Locator points to an element with a given [aria errormessage](https://w3c.github.io/aria/#aria-errormessage). + +### UI updates + +* New button in Codegen for picking elements to produce aria snapshots. +* Additional details (such as keys pressed) are now displayed alongside action API calls in traces. +* Display of `canvas` content in traces is error-prone. Display is now disabled by default, and can be enabled via the `Display canvas content` UI setting. +* `Call` and `Network` panels now display additional time information. + +### Breaking + +* [`method: LocatorAssertions.toBeEditable`] and [`method: Locator.isEditable`] now throw if the target element is not ``, ` - + + ``` diff --git a/docs/src/release-notes-java.md b/docs/src/release-notes-java.md index 651d2890da08d..6649a1d1c8d2b 100644 --- a/docs/src/release-notes-java.md +++ b/docs/src/release-notes-java.md @@ -4,11 +4,84 @@ title: "Release notes" toc_max_heading_level: 2 --- +## Version 1.51 + +### Highlights + +* New option [`option: BrowserContext.storageState.indexedDB`] for [`method: BrowserContext.storageState`] allows to save and restore IndexedDB contents. Useful when your application uses [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) to store authentication tokens, like Firebase Authentication. + + Here is an example following the [authentication guide](./auth.md#reusing-signed-in-state): + + ```java + // Save storage state into the file. Make sure to include IndexedDB. + context.storageState(new BrowserContext.StorageStateOptions() + .setPath(Paths.get("state.json")) + .setIndexedDB(true)); + + // Create a new context with the saved storage state. + BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setStorageStatePath(Paths.get("state.json"))); + ``` + +* New option [`option: Locator.filter.visible`] for [`method: Locator.filter`] allows matching only visible elements. + + ```java + // Ignore invisible todo items. + Locator todoItems = page.getByTestId("todo-item") + .filter(new Locator.FilterOptions().setVisible(true)); + // Check there are exactly 3 visible ones. + assertThat(todoItems).hasCount(3); + ``` + +* New option `setContrast` for methods [`method: Page.emulateMedia`] and [`method: Browser.newContext`] allows to emulate the `prefers-contrast` media feature. + +* New option [`option: APIRequest.newContext.failOnStatusCode`] makes all fetch requests made through the [APIRequestContext] throw on response codes other than 2xx and 3xx. + +### Browser Versions + +* Chromium 134.0.6998.35 +* Mozilla Firefox 135.0 +* WebKit 18.4 + +This version was also tested against the following stable channels: + +* Google Chrome 133 +* Microsoft Edge 133 + + +## Version 1.50 + +### Miscellaneous + +* Added method [`method: LocatorAssertions.toHaveAccessibleErrorMessage`] to assert the Locator points to an element with a given [aria errormessage](https://w3c.github.io/aria/#aria-errormessage). + +### UI updates + +* New button in Codegen for picking elements to produce aria snapshots. +* Additional details (such as keys pressed) are now displayed alongside action API calls in traces. +* Display of `canvas` content in traces is error-prone. Display is now disabled by default, and can be enabled via the `Display canvas content` UI setting. +* `Call` and `Network` panels now display additional time information. + +### Breaking + +* [`method: LocatorAssertions.toBeEditable`] and [`method: Locator.isEditable`] now throw if the target element is not ``, ` - + + ``` diff --git a/docs/src/release-notes-js.md b/docs/src/release-notes-js.md index 9d26d415510a3..4083014edbb82 100644 --- a/docs/src/release-notes-js.md +++ b/docs/src/release-notes-js.md @@ -6,6 +6,168 @@ toc_max_heading_level: 2 import LiteYouTube from '@site/src/components/LiteYouTube'; +## Version 1.51 + +### StorageState for indexedDB + +* New option [`option: BrowserContext.storageState.indexedDB`] for [`method: BrowserContext.storageState`] allows to save and restore IndexedDB contents. Useful when your application uses [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) to store authentication tokens, like Firebase Authentication. + + Here is an example following the [authentication guide](./auth.md#basic-shared-account-in-all-tests): + + ```js title="tests/auth.setup.ts" + import { test as setup, expect } from '@playwright/test'; + import path from 'path'; + + const authFile = path.join(__dirname, '../playwright/.auth/user.json'); + + setup('authenticate', async ({ page }) => { + await page.goto('/'); + // ... perform authentication steps ... + + // make sure to save indexedDB + await page.context().storageState({ path: authFile, indexedDB: true }); + }); + ``` + +### Copy as prompt + +New "Copy prompt" button on errors in the HTML report, trace viewer and UI mode. Click to copy a pre-filled LLM prompt that contains the error message and useful context for fixing the error. + + ![Copy prompt](https://github.com/user-attachments/assets/f3654407-dd6d-4240-9845-0d96df2bf30a) + +### Filter visible elements + +New option [`option: Locator.filter.visible`] for [`method: Locator.filter`] allows matching only visible elements. + + ```js title="example.spec.ts" + test('some test', async ({ page }) => { + // Ignore invisible todo items. + const todoItems = page.getByTestId('todo-item').filter({ visible: true }); + // Check there are exactly 3 visible ones. + await expect(todoItems).toHaveCount(3); + }); + ``` + +### Git information in HTML report + +Set option [`property: TestConfig.captureGitInfo`] to capture git information into [`property: TestConfig.metadata`]. + + ```js title="playwright.config.ts" + import { defineConfig } from '@playwright/test'; + + export default defineConfig({ + captureGitInfo: { commit: true, diff: true } + }); + ``` + + HTML report will show this information when available: + + ![Git information in the report](https://github.com/user-attachments/assets/f5b3f6f4-aa08-4a24-816c-7edf33ef0c37) + +### Test Step improvements + +A new [TestStepInfo] object is now available in test steps. You can add step attachments or skip the step under some conditions. + + ```js + test('some test', async ({ page, isMobile }) => { + // Note the new "step" argument: + await test.step('here is my step', async step => { + step.skip(isMobile, 'not relevant on mobile layouts'); + + // ... + await step.attach('my attachment', { body: 'some text' }); + // ... + }); + }); + ``` + +### Miscellaneous + +* New option `contrast` for methods [`method: Page.emulateMedia`] and [`method: Browser.newContext`] allows to emulate the `prefers-contrast` media feature. +* New option [`option: APIRequest.newContext.failOnStatusCode`] makes all fetch requests made through the [APIRequestContext] throw on response codes other than 2xx and 3xx. +* Assertion [`method: PageAssertions.toHaveURL`] now supports a predicate. + +### Browser Versions + +* Chromium 134.0.6998.35 +* Mozilla Firefox 135.0 +* WebKit 18.4 + +This version was also tested against the following stable channels: + +* Google Chrome 133 +* Microsoft Edge 133 + + +## Version 1.50 + +### Test runner + +* New option [`option: Test.step.timeout`] allows specifying a maximum run time for an individual test step. A timed-out step will fail the execution of the test. + + ```js + test('some test', async ({ page }) => { + await test.step('a step', async () => { + // This step can time out separately from the test + }, { timeout: 1000 }); + }); + ``` + +* New method [`method: Test.step.skip`] to disable execution of a test step. + + ```js + test('some test', async ({ page }) => { + await test.step('before running step', async () => { + // Normal step + }); + + await test.step.skip('not yet ready', async () => { + // This step is skipped + }); + + await test.step('after running step', async () => { + // This step still runs even though the previous one was skipped + }); + }); + ``` + +* Expanded [`method: LocatorAssertions.toMatchAriaSnapshot#2`] to allow storing of aria snapshots in separate YAML files. +* Added method [`method: LocatorAssertions.toHaveAccessibleErrorMessage`] to assert the Locator points to an element with a given [aria errormessage](https://w3c.github.io/aria/#aria-errormessage). +* Option [`property: TestConfig.updateSnapshots`] added the configuration enum `changed`. `changed` updates only the snapshots that have changed, whereas `all` now updates all snapshots, regardless of whether there are any differences. +* New option [`property: TestConfig.updateSourceMethod`] defines the way source code is updated when [`property: TestConfig.updateSnapshots`] is configured. Added `overwrite` and `3-way` modes that write the changes into source code, on top of existing `patch` mode that creates a patch file. + + ```bash + npx playwright test --update-snapshots=changed --update-source-method=3way + ``` + +* Option [`property: TestConfig.webServer`] added a `gracefulShutdown` field for specifying a process kill signal other than the default `SIGKILL`. +* Exposed [`property: TestStep.attachments`] from the reporter API to allow retrieval of all attachments created by that step. +* New option `pathTemplate` for `toHaveScreenshot` and `toMatchAriaSnapshot` assertions in the [`property: TestConfig.expect`] configuration. + +### UI updates + +* Updated default HTML reporter to improve display of attachments. +* New button in Codegen for picking elements to produce aria snapshots. +* Additional details (such as keys pressed) are now displayed alongside action API calls in traces. +* Display of `canvas` content in traces is error-prone. Display is now disabled by default, and can be enabled via the `Display canvas content` UI setting. +* `Call` and `Network` panels now display additional time information. + +### Breaking + +* [`method: LocatorAssertions.toBeEditable`] and [`method: Locator.isEditable`] now throw if the target element is not ``, ` ``` diff --git a/docs/src/release-notes-python.md b/docs/src/release-notes-python.md index 14f84f395c219..c0fdc32e25693 100644 --- a/docs/src/release-notes-python.md +++ b/docs/src/release-notes-python.md @@ -4,11 +4,84 @@ title: "Release notes" toc_max_heading_level: 2 --- +## Version 1.51 + +### Highlights + +* New option [`option: BrowserContext.storageState.indexedDB`] for [`method: BrowserContext.storageState`] allows to save and restore IndexedDB contents. Useful when your application uses [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) to store authentication tokens, like Firebase Authentication. + + Here is an example following the [authentication guide](./auth.md#reusing-signed-in-state): + + ```python + # Save storage state into the file. Make sure to include IndexedDB. + storage = await context.storage_state(path="state.json", indexed_db=True) + + # Create a new context with the saved storage state. + context = await browser.new_context(storage_state="state.json") + ``` + +* New option [`option: Locator.filter.visible`] for [`method: Locator.filter`] allows matching only visible elements. + + ```python + # Ignore invisible todo items. + todo_items = page.get_by_test_id("todo-item").filter(visible=True) + # Check there are exactly 3 visible ones. + await expect(todo_items).to_have_count(3) + ``` + +* New option `contrast` for methods [`method: Page.emulateMedia`] and [`method: Browser.newContext`] allows to emulate the `prefers-contrast` media feature. + +* New option [`option: APIRequest.newContext.failOnStatusCode`] makes all fetch requests made through the [APIRequestContext] throw on response codes other than 2xx and 3xx. + +### Browser Versions + +* Chromium 134.0.6998.35 +* Mozilla Firefox 135.0 +* WebKit 18.4 + +This version was also tested against the following stable channels: + +* Google Chrome 133 +* Microsoft Edge 133 + + +## Version 1.50 + +### Async Pytest Plugin + +* [Playwright's Pytest plugin](./test-runners.md) now has support for [Async Fixtures](https://playwright.dev/python/docs/test-runners#async-fixtures). + +### Miscellaneous + +* Added method [`method: LocatorAssertions.toHaveAccessibleErrorMessage`] to assert the Locator points to an element with a given [aria errormessage](https://w3c.github.io/aria/#aria-errormessage). + +### UI updates + +* New button in Codegen for picking elements to produce aria snapshots. +* Additional details (such as keys pressed) are now displayed alongside action API calls in traces. +* Display of `canvas` content in traces is error-prone. Display is now disabled by default, and can be enabled via the `Display canvas content` UI setting. +* `Call` and `Network` panels now display additional time information. + +### Breaking + +* [`method: LocatorAssertions.toBeEditable`] and [`method: Locator.isEditable`] now throw if the target element is not ``, ` - + + ``` diff --git a/docs/src/test-api/class-fullconfig.md b/docs/src/test-api/class-fullconfig.md index 923c9fa858fe2..edbc991bfd7ec 100644 --- a/docs/src/test-api/class-fullconfig.md +++ b/docs/src/test-api/class-fullconfig.md @@ -93,8 +93,8 @@ See [`property: TestConfig.reporter`]. ## property: FullConfig.reportSlowTests * since: v1.10 - type: <[null]|[Object]> - - `max` <[int]> The maximum number of slow test files to report. Defaults to `5`. - - `threshold` <[float]> Test duration in milliseconds that is considered slow. Defaults to 15 seconds. + - `max` <[int]> The maximum number of slow test files to report. + - `threshold` <[float]> Test file duration in milliseconds that is considered slow. See [`property: TestConfig.reportSlowTests`]. diff --git a/docs/src/test-api/class-test.md b/docs/src/test-api/class-test.md index 00c7a5f0eea26..eefaeb4246ce8 100644 --- a/docs/src/test-api/class-test.md +++ b/docs/src/test-api/class-test.md @@ -1751,7 +1751,7 @@ Step name. ### param: Test.step.body * since: v1.10 -- `body` <[function]\(\):[Promise]<[any]>> +- `body` <[function]\([TestStepInfo]\):[Promise]<[any]>> Step body. @@ -1771,7 +1771,9 @@ Specifies a custom location for the step to be shown in test reports and trace v * since: v1.50 - returns: <[void]> -Mark a test step as "skip" to temporarily disable its execution, useful for steps that are currently failing and planned for a near-term fix. Playwright will not run the step. +Mark a test step as "skip" to temporarily disable its execution, useful for steps that are currently failing and planned for a near-term fix. Playwright will not run the step. See also [`method: TestStepInfo.skip#2`]. + +We recommend [`method: TestStepInfo.skip#1`] instead. **Usage** @@ -1822,7 +1824,7 @@ Maximum time in milliseconds for the step to finish. Defaults to `0` (no timeout * since: v1.50 - `timeout` <[float]> -Maximum time in milliseconds for the step to finish. Defaults to `0` (no timeout). +The maximum time, in milliseconds, allowed for the step to complete. If the step does not complete within the specified timeout, the [`method: Test.step`] method will throw a [TimeoutError]. Defaults to `0` (no timeout). ## method: Test.use * since: v1.10 diff --git a/docs/src/test-api/class-testconfig.md b/docs/src/test-api/class-testconfig.md index 5a67ea36d4649..c2d29d0eb40f2 100644 --- a/docs/src/test-api/class-testconfig.md +++ b/docs/src/test-api/class-testconfig.md @@ -36,6 +36,38 @@ export default defineConfig({ }); ``` +## property: TestConfig.captureGitInfo +* since: v1.51 +- type: ?<[Object]> + - `commit` ? Whether to capture commit and pull request information such as hash, author, timestamp. + - `diff` ? Whether to capture commit diff. + +These settings control whether git information is captured and stored in the config [`property: TestConfig.metadata`]. + +**Usage** + +```js title="playwright.config.ts" +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + captureGitInfo: { commit: true, diff: true } +}); +``` + +**Details** + +* Capturing `commit` information is useful when you'd like to see it in your HTML (or a third party) report. +* Capturing `diff` information is useful to enrich the report with the actual source diff. This information can be used to provide intelligent advice on how to fix the test. + +:::note +Default values for these settings depend on the environment. When tests run as a part of CI where it is safe to obtain git information, the default value is `true`, `false` otherwise. +::: + +:::note +The structure of the git commit metadata is subject to change. +::: + + ## property: TestConfig.expect * since: v1.10 - type: ?<[Object]> @@ -48,6 +80,9 @@ export default defineConfig({ - `scale` ?<[ScreenshotScale]<"css"|"device">> See [`option: Page.screenshot.scale`] in [`method: Page.screenshot`]. Defaults to `"css"`. - `stylePath` ?<[string]|[Array]<[string]>> See [`option: Page.screenshot.style`] in [`method: Page.screenshot`]. - `threshold` ?<[float]> An acceptable perceived color difference between the same pixel in compared images, ranging from `0` (strict) and `1` (lax). `"pixelmatch"` comparator computes color difference in [YIQ color space](https://en.wikipedia.org/wiki/YIQ) and defaults `threshold` value to `0.2`. + - `pathTemplate` ?<[string]> A template controlling location of the screenshots. See [`property: TestConfig.snapshotPathTemplate`] for details. + - `toMatchAriaSnapshot` ?<[Object]> Configuration for the [`method: LocatorAssertions.toMatchAriaSnapshot#2`] method. + - `pathTemplate` ?<[string]> A template controlling location of the aria snapshots. See [`property: TestConfig.snapshotPathTemplate`] for details. - `toMatchSnapshot` ?<[Object]> Configuration for the [`method: SnapshotAssertions.toMatchSnapshot#1`] method. - `maxDiffPixels` ?<[int]> An acceptable amount of pixels that could be different, unset by default. - `maxDiffPixelRatio` ?<[float]> An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default. @@ -234,7 +269,7 @@ export default defineConfig({ * since: v1.10 - type: ?<[Metadata]> -Metadata that will be put directly to the test report serialized as JSON. +Metadata contains key-value pairs to be included in the report. For example, HTML report will display it as key-value pairs, and JSON report will include metadata serialized as json. **Usage** @@ -242,7 +277,7 @@ Metadata that will be put directly to the test report serialized as JSON. import { defineConfig } from '@playwright/test'; export default defineConfig({ - metadata: 'acceptance tests', + metadata: { title: 'acceptance tests' }, }); ``` @@ -421,7 +456,7 @@ export default defineConfig({ * since: v1.10 - type: ?<[null]|[Object]> - `max` <[int]> The maximum number of slow test files to report. Defaults to `5`. - - `threshold` <[float]> Test duration in milliseconds that is considered slow. Defaults to 15 seconds. + - `threshold` <[float]> Test file duration in milliseconds that is considered slow. Defaults to 5 minutes. Whether to report slow test files. Pass `null` to disable this feature. @@ -629,9 +664,9 @@ export default defineConfig({ - `stdout` ?<["pipe"|"ignore"]> If `"pipe"`, it will pipe the stdout of the command to the process stdout. If `"ignore"`, it will ignore the stdout of the command. Default to `"ignore"`. - `stderr` ?<["pipe"|"ignore"]> Whether to pipe the stderr of the command to the process stderr or ignore it. Defaults to `"pipe"`. - `timeout` ?<[int]> How long to wait for the process to start up and be available in milliseconds. Defaults to 60000. - - `gracefulShutdown` ?<[Object]> How to shut down the process. If unspecified, the process group is forcefully `SIGKILL`ed. If set to `{ signal: 'SIGINT', timeout: 500 }`, the process group is sent a `SIGINT` signal, followed by `SIGKILL` if it doesn't exit within 500ms. You can also use `SIGTERM` instead. A `0` timeout means no `SIGKILL` will be sent. Windows doesn't support `SIGINT` and `SIGTERM` signals, so this option is ignored. + - `gracefulShutdown` ?<[Object]> How to shut down the process. If unspecified, the process group is forcefully `SIGKILL`ed. If set to `{ signal: 'SIGTERM', timeout: 500 }`, the process group is sent a `SIGTERM` signal, followed by `SIGKILL` if it doesn't exit within 500ms. You can also use `SIGINT` as the signal instead. A `0` timeout means no `SIGKILL` will be sent. Windows doesn't support `SIGTERM` and `SIGINT` signals, so this option is ignored on Windows. Note that shutting down a Docker container requires `SIGTERM`. - `signal` <["SIGINT"|"SIGTERM"]> - - `timeout` <[int]> + - `timeout` <[int]> - `url` ?<[string]> The url on your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the server is ready to accept connections. Redirects (3xx status codes) are being followed and the new location is checked. Either `port` or `url` should be specified. Launch a development web server (or multiple) during the tests. @@ -655,7 +690,7 @@ import { defineConfig } from '@playwright/test'; export default defineConfig({ webServer: { command: 'npm run start', - url: 'http://127.0.0.1:3000', + url: 'http://localhost:3000', timeout: 120 * 1000, reuseExistingServer: !process.env.CI, }, @@ -684,19 +719,19 @@ export default defineConfig({ webServer: [ { command: 'npm run start', - url: 'http://127.0.0.1:3000', + url: 'http://localhost:3000', timeout: 120 * 1000, reuseExistingServer: !process.env.CI, }, { command: 'npm run backend', - url: 'http://127.0.0.1:3333', + url: 'http://localhost:3333', timeout: 120 * 1000, reuseExistingServer: !process.env.CI, } ], use: { - baseURL: 'http://127.0.0.1:3000', + baseURL: 'http://localhost:3000', }, }); ``` diff --git a/docs/src/test-api/class-testproject.md b/docs/src/test-api/class-testproject.md index d93286fa26aa2..17fecf69309ae 100644 --- a/docs/src/test-api/class-testproject.md +++ b/docs/src/test-api/class-testproject.md @@ -98,6 +98,9 @@ export default defineConfig({ - `caret` ?<[ScreenshotCaret]<"hide"|"initial">> See [`option: Page.screenshot.caret`] in [`method: Page.screenshot`]. Defaults to `"hide"`. - `scale` ?<[ScreenshotScale]<"css"|"device">> See [`option: Page.screenshot.scale`] in [`method: Page.screenshot`]. Defaults to `"css"`. - `stylePath` ?<[string]|[Array]<[string]>> See [`option: Page.screenshot.style`] in [`method: Page.screenshot`]. + - `pathTemplate` ?<[string]> A template controlling location of the screenshots. See [`property: TestProject.snapshotPathTemplate`] for details. + - `toMatchAriaSnapshot` ?<[Object]> Configuration for the [`method: LocatorAssertions.toMatchAriaSnapshot#2`] method. + - `pathTemplate` ?<[string]> A template controlling location of the aria snapshots. See [`property: TestProject.snapshotPathTemplate`] for details. - `toMatchSnapshot` ?<[Object]> Configuration for the [`method: SnapshotAssertions.toMatchSnapshot#1`] method. - `threshold` ?<[float]> an acceptable perceived color difference between the same pixel in compared images, ranging from `0` (strict) and `1` (lax). `"pixelmatch"` comparator computes color difference in [YIQ color space](https://en.wikipedia.org/wiki/YIQ) and defaults `threshold` value to `0.2`. - `maxDiffPixels` ?<[int]> an acceptable amount of pixels that could be different, unset by default. @@ -180,6 +183,10 @@ Metadata that will be put directly to the test report serialized as JSON. Project name is visible in the report and during test execution. +:::warning +Playwright executes the configuration file multiple times. Do not dynamically produce non-stable values in your configuration. +::: + ## property: TestProject.snapshotDir * since: v1.10 - type: ?<[string]> diff --git a/docs/src/test-api/class-teststepinfo.md b/docs/src/test-api/class-teststepinfo.md new file mode 100644 index 0000000000000..0a0b521debedc --- /dev/null +++ b/docs/src/test-api/class-teststepinfo.md @@ -0,0 +1,130 @@ +# class: TestStepInfo +* since: v1.51 +* langs: js + +`TestStepInfo` contains information about currently running test step. It is passed as an argument to the step function. `TestStepInfo` provides utilities to control test step execution. + +```js +import { test, expect } from '@playwright/test'; + +test('basic test', async ({ page, browserName }) => { + await test.step('check some behavior', async step => { + step.skip(browserName === 'webkit', 'The feature is not available in WebKit'); + // ... rest of the step code + }); +}); +``` + +## async method: TestStepInfo.attach +* since: v1.51 + +Attach a value or a file from disk to the current test step. Some reporters show test step attachments. Either [`option: path`] or [`option: body`] must be specified, but not both. Calling this method will attribute the attachment to the step, as opposed to [`method: TestInfo.attach`] which stores all attachments at the test level. + +For example, you can attach a screenshot to the test step: + +```js +import { test, expect } from '@playwright/test'; + +test('basic test', async ({ page }) => { + await page.goto('https://playwright.dev'); + await test.step('check page rendering', async step => { + const screenshot = await page.screenshot(); + await step.attach('screenshot', { body: screenshot, contentType: 'image/png' }); + }); +}); +``` + +Or you can attach files returned by your APIs: + +```js +import { test, expect } from '@playwright/test'; +import { download } from './my-custom-helpers'; + +test('basic test', async ({}) => { + await test.step('check download behavior', async step => { + const tmpPath = await download('a'); + await step.attach('downloaded', { path: tmpPath }); + }); +}); +``` + +:::note +[`method: TestStepInfo.attach`] automatically takes care of copying attached files to a +location that is accessible to reporters. You can safely remove the attachment +after awaiting the attach call. +::: + +### param: TestStepInfo.attach.name +* since: v1.51 +- `name` <[string]> + +Attachment name. The name will also be sanitized and used as the prefix of file name +when saving to disk. + +### option: TestStepInfo.attach.body +* since: v1.51 +- `body` <[string]|[Buffer]> + +Attachment body. Mutually exclusive with [`option: path`]. + +### option: TestStepInfo.attach.contentType +* since: v1.51 +- `contentType` <[string]> + +Content type of this attachment to properly present in the report, for example `'application/json'` or `'image/png'`. If omitted, content type is inferred based on the [`option: path`], or defaults to `text/plain` for [string] attachments and `application/octet-stream` for [Buffer] attachments. + +### option: TestStepInfo.attach.path +* since: v1.51 +- `path` <[string]> + +Path on the filesystem to the attached file. Mutually exclusive with [`option: body`]. + +## method: TestStepInfo.skip#1 +* since: v1.51 + +Abort the currently running step and mark it as skipped. Useful for steps that are currently failing and planned for a near-term fix. + +**Usage** + +```js +import { test, expect } from '@playwright/test'; + +test('my test', async ({ page }) => { + await test.step('check expectations', async step => { + step.skip(); + // step body below will not run + // ... + }); +}); +``` + +## method: TestStepInfo.skip#2 +* since: v1.51 + +Conditionally abort the currently running step and mark it as skipped with an optional description. Useful for steps that should not be executed in some cases. + +**Usage** + +```js +import { test, expect } from '@playwright/test'; + +test('my test', async ({ page, isMobile }) => { + await test.step('check desktop expectations', async step => { + step.skip(isMobile, 'not present in the mobile layout'); + // step body below will not run + // ... + }); +}); +``` + +### param: TestStepInfo.skip#2.condition +* since: v1.51 +- `condition` <[boolean]> + +A skip condition. Test step is skipped when the condition is `true`. + +### param: TestStepInfo.skip#2.description +* since: v1.51 +- `description` ?<[string]> + +Optional description that will be reflected in a test report. diff --git a/docs/src/test-cli-js.md b/docs/src/test-cli-js.md index 72068d57cf74a..2bfc655d1e620 100644 --- a/docs/src/test-cli-js.md +++ b/docs/src/test-cli-js.md @@ -110,6 +110,7 @@ Complete set of Playwright Test options is available in the [configuration file] | `--ui` | Run tests in interactive UI mode. | | `--ui-host ` | Host to serve UI on; specifying this option opens UI in a browser tab. | | `--ui-port ` | Port to serve UI on, 0 for any free port; specifying this option opens UI in a browser tab. | -| `-u` or `--update-snapshots [mode]` | Update snapshots with actual results. Possible values are "all", "changed", "missing", and "none". Not passing defaults to "missing"; passing without a value defaults to "changed". | +| `-u` or `--update-snapshots [mode]` | Update snapshots with actual results. Possible values are "all", "changed", "missing", and "none". Running tests without the flag defaults to "missing"; running tests with the flag but without a value defaults to "changed". | +| `--update-source-method [mode]` | Update snapshots with actual results. Possible values are "patch" (default), "3way" and "overwrite". "Patch" creates a unified diff file that can be used to update the source code later. "3way" generates merge conflict markers in source code. "Overwrite" overwrites the source code with the new snapshot values.| | `-j ` or `--workers ` | Number of concurrent workers or percentage of logical CPU cores, use 1 to run in a single worker (default: 50%). | | `-x` | Stop after the first failure. | diff --git a/docs/src/test-components-js.md b/docs/src/test-components-js.md index 9a28edd40e26a..9559989571503 100644 --- a/docs/src/test-components-js.md +++ b/docs/src/test-components-js.md @@ -853,6 +853,14 @@ export default defineConfig({ }); ``` +### How do I use CSS imports? + +If you have a component that imports CSS, Vite will handle it automatically. You can also use CSS pre-processors such as Sass, Less, or Stylus, and Vite will handle them as well without any additional configuration. However, corresponding CSS pre-processor needs to be installed. + +Vite has a hard requirement that all CSS Modules are named `*.module.[css extension]`. If you have a custom build config for your project normally and have imports of the form `import styles from 'styles.css'` you must rename your files to properly indicate they are to be treated as modules. You could also write a Vite plugin to handle this for you. + +Check [Vite documentation](https://vite.dev/guide/features#css) for more details. + ### How can I test components that uses Pinia? Pinia needs to be initialized in `playwright/index.{js,ts,jsx,tsx}`. If you do this inside a `beforeMount` hook, the `initialState` can be overwritten on a per-test basis: diff --git a/docs/src/test-configuration-js.md b/docs/src/test-configuration-js.md index 822bd4ea0d24b..e3831c19112d6 100644 --- a/docs/src/test-configuration-js.md +++ b/docs/src/test-configuration-js.md @@ -35,7 +35,7 @@ export default defineConfig({ use: { // Base URL to use in actions like `await page.goto('/')`. - baseURL: 'http://127.0.0.1:3000', + baseURL: 'http://localhost:3000', // Collect trace when retrying the failed test. trace: 'on-first-retry', @@ -50,7 +50,7 @@ export default defineConfig({ // Run your local dev server before starting the tests. webServer: { command: 'npm run start', - url: 'http://127.0.0.1:3000', + url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, }, }); diff --git a/docs/src/test-fixtures-js.md b/docs/src/test-fixtures-js.md index 9bdd4391adade..fc571477f981a 100644 --- a/docs/src/test-fixtures-js.md +++ b/docs/src/test-fixtures-js.md @@ -407,8 +407,8 @@ Automatic fixtures are set up for each test/worker, even when the test does not Here is an example fixture that automatically attaches debug logs when the test fails, so we can later review the logs in the reporter. Note how it uses [TestInfo] object that is available in each test/fixture to retrieve metadata about the test being run. ```js title="my-test.ts" -import * as debug from 'debug'; -import * as fs from 'fs'; +import debug from 'debug'; +import fs from 'fs'; import { test as base } from '@playwright/test'; export const test = base.extend<{ saveLogs: void }>({ diff --git a/docs/src/test-reporter-api/class-teststep.md b/docs/src/test-reporter-api/class-teststep.md index ef16e4849ac22..1272eb546faad 100644 --- a/docs/src/test-reporter-api/class-teststep.md +++ b/docs/src/test-reporter-api/class-teststep.md @@ -50,6 +50,14 @@ Start time of this particular test step. List of steps inside this step. +## property: TestStep.annotations +* since: v1.51 +- type: <[Array]<[Object]>> + - `type` <[string]> Annotation type, for example `'skip'`. + - `description` ?<[string]> Optional description. + +The list of annotations applicable to the current test step. + ## property: TestStep.attachments * since: v1.50 - type: <[Array]<[Object]>> diff --git a/docs/src/test-runners-python.md b/docs/src/test-runners-python.md index 3f93dd6504a1f..22c9e420dd302 100644 --- a/docs/src/test-runners-python.md +++ b/docs/src/test-runners-python.md @@ -263,7 +263,7 @@ See the [guides for CI providers](./ci.md) to deploy your tests to CI/CD. ## Async Fixtures If you want to use async fixtures, you can use the [`pytest-playwright-asyncio`](https://pypi.org/project/pytest-playwright-asyncio/) plugin. -Make sure to use `pytest-asyncio>=0.24.0` and make your tests use of [`loop_scope=sesion`](https://pytest-asyncio.readthedocs.io/en/latest/how-to-guides/run_session_tests_in_same_loop.html). +Make sure to use `pytest-asyncio>=0.24.0` and make your tests use of [`loop_scope=session`](https://pytest-asyncio.readthedocs.io/en/latest/how-to-guides/run_session_tests_in_same_loop.html). ```python import pytest diff --git a/docs/src/test-snapshots-js.md b/docs/src/test-snapshots-js.md index a1ece1a6e51c1..6a8d42e88656f 100644 --- a/docs/src/test-snapshots-js.md +++ b/docs/src/test-snapshots-js.md @@ -48,7 +48,7 @@ The snapshot name `example-test-1-chromium-darwin.png` consists of a few parts: - `chromium-darwin` - the browser name and the platform. Screenshots differ between browsers and platforms due to different rendering, fonts and more, so you will need different snapshots for them. If you use multiple projects in your [configuration file](./test-configuration.md), project name will be used instead of `chromium`. -The snapshot name and path can be configured with [`snapshotPathTemplate`](./api/class-testproject#test-project-snapshot-path-template) in the playwright config. +The snapshot name and path can be configured with [`property: TestConfig.snapshotPathTemplate`] in the playwright config. ## Updating screenshots diff --git a/docs/src/test-ui-mode-js.md b/docs/src/test-ui-mode-js.md index 41a00264d9b5d..4aaeae92d63ef 100644 --- a/docs/src/test-ui-mode-js.md +++ b/docs/src/test-ui-mode-js.md @@ -18,12 +18,13 @@ UI Mode lets you explore, run, and debug tests with a time travel experience com To open UI mode, run the following command in your terminal: - ```bash - npx playwright test --ui - ``` +```bash +npx playwright test --ui +``` + ## Running your tests -Once you launch UI Mode you will see a list of all your test files. You can run all your tests by clicking the triangle icon in the sidebar. You can also run a single test file, a block of tests or a single test by hovering over the name and clicking on the triangle next to it. +Once you launch UI Mode you will see a list of all your test files. You can run all your tests by clicking the triangle icon in the sidebar. You can also run a single test file, a block of tests or a single test by hovering over the name and clicking on the triangle next to it. ![running tests in ui mode](https://github.com/microsoft/playwright/assets/13063165/6b87712f-64a5-4d73-a91d-6562b864712c) @@ -33,17 +34,15 @@ Filter tests by text or `@tag` or by passed, failed or skipped tests. You can al ![filtering tests in ui mode](https://github.com/microsoft/playwright/assets/13063165/6f05e589-036d-45d5-9078-38134e1261e4) - ## Timeline view At the top of the trace you can see a timeline view of your test with different colors to highlight navigation and actions. Hover back and forth to see an image snapshot for each action. Double click on an action to see the time range for that action. You can use the slider in the timeline to increase the actions selected and these will be shown in the Actions tab and all console logs and network logs will be filtered to only show the logs for the actions selected. ![timeline view in ui mode](https://github.com/microsoft/playwright/assets/13063165/811a9985-32aa-4a3e-9869-de32053cf468) - ## Actions -In the Actions tab you can see what locator was used for every action and how long each one took to run. Hover over each action of your test and visually see the change in the DOM snapshot. Go back and forward in time and click an action to inspect and debug. Use the Before and After tabs to visually see what happened before and after the action. +In the Actions tab you can see what locator was used for every action and how long each one took to run. Hover over each action of your test and visually see the change in the DOM snapshot. Go back and forward in time and click an action to inspect and debug. Use the Before and After tabs to visually see what happened before and after the action. ![use before and after actions in ui mode](https://github.com/microsoft/playwright/assets/13063165/7b22fab5-7346-4b98-8fdd-a78ed280647f) ## Pop out and inspect the DOM @@ -60,7 +59,7 @@ Click on the pick locator button and hover over the DOM snapshot to see the loca ## Source -As you hover over each action of your test the line of code for that action is highlighted in the source panel. +As you hover over each action of your test the line of code for that action is highlighted in the source panel. The button "Open in VSCode" is at the top-right of this section. Upon clicking the button, it will open your test in VS Code right at the line of code that you clicked on. ![showing source code of tests in ui mode](https://github.com/microsoft/playwright/assets/13063165/49b9fa2a-8a57-4044-acaa-0a2ea4784c5c) @@ -108,7 +107,7 @@ Next to the Actions tab you will find the Metadata tab which will show you more ## Watch mode -Next to the name of each test in the sidebar you will find an eye icon. Clicking on the icon will activate watch mode which will re-run the test when you make changes to it. You can watch a number of tests at the same time be clicking the eye icon next to each one or all tests by clicking the eye icon at the top of the sidebar. If you are using VS Code then you can easily open your test by clicking on the file icon next to the eye icon. This will open your test in VS Code right at the line of code that you clicked on. +Next to the name of each test in the sidebar you will find an eye icon. Clicking on the icon will activate watch mode which will re-run the test when you make changes to it. You can watch a number of tests at the same time be clicking the eye icon next to each one or all tests by clicking the eye icon at the top of the sidebar. ![watch mode in ui mode](https://github.com/microsoft/playwright/assets/13063165/20d7d44c-b52d-43ff-8871-8b828671f3da) diff --git a/docs/src/test-use-options-js.md b/docs/src/test-use-options-js.md index 6e1da0a228ce1..12f97db46dc2c 100644 --- a/docs/src/test-use-options-js.md +++ b/docs/src/test-use-options-js.md @@ -17,7 +17,7 @@ import { defineConfig } from '@playwright/test'; export default defineConfig({ use: { // Base URL to use in actions like `await page.goto('/')`. - baseURL: 'http://127.0.0.1:3000', + baseURL: 'http://localhost:3000', // Populates context with given storage state. storageState: 'state.json', diff --git a/docs/src/test-webserver-js.md b/docs/src/test-webserver-js.md index f4c86197c0e8d..d4a7bbb19b63f 100644 --- a/docs/src/test-webserver-js.md +++ b/docs/src/test-webserver-js.md @@ -18,7 +18,7 @@ export default defineConfig({ // Run your local dev server before starting the tests webServer: { command: 'npm run start', - url: 'http://127.0.0.1:3000', + url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, stdout: 'ignore', stderr: 'pipe', @@ -37,7 +37,7 @@ export default defineConfig({ | `stdout` | If `"pipe"`, it will pipe the stdout of the command to the process stdout. If `"ignore"`, it will ignore the stdout of the command. Default to `"ignore"`. | | `stderr` | Whether to pipe the stderr of the command to the process stderr or ignore it. Defaults to `"pipe"`. | | `timeout` | How long to wait for the process to start up and be available in milliseconds. Defaults to 60000. | -| `gracefulShutdown` | How to shut down the process. If unspecified, the process group is forcefully `SIGKILL`ed. If set to `{ signal: 'SIGINT', timeout: 500 }`, the process group is sent a `SIGINT` signal, followed by `SIGKILL` if it doesn't exit within 500ms. You can also use `SIGTERM` instead. A `0` timeout means no `SIGKILL` will be sent. Windows doesn't support `SIGINT` and `SIGTERM` signals, so this option is ignored. | +| `gracefulShutdown` | How to shut down the process. If unspecified, the process group is forcefully `SIGKILL`ed. If set to `{ signal: 'SIGTERM', timeout: 500 }`, the process group is sent a `SIGTERM` signal, followed by `SIGKILL` if it doesn't exit within 500ms. You can also use `SIGINT` as the signal instead. A `0` timeout means no `SIGKILL` will be sent. Windows doesn't support `SIGTERM` and `SIGINT` signals, so this option is ignored on Windows. Note that shutting down a Docker container requires `SIGTERM`. | ## Adding a server timeout @@ -52,7 +52,7 @@ export default defineConfig({ // Run your local dev server before starting the tests webServer: { command: 'npm run start', - url: 'http://127.0.0.1:3000', + url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, timeout: 120 * 1000, }, @@ -63,7 +63,7 @@ export default defineConfig({ It is also recommended to specify the `baseURL` in the `use: {}` section of your config, so that tests can use relative urls and you don't have to specify the full URL over and over again. -When using [`method: Page.goto`], [`method: Page.route`], [`method: Page.waitForURL`], [`method: Page.waitForRequest`], or [`method: Page.waitForResponse`] it takes the base URL in consideration by using the [`URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor for building the corresponding URL. For Example, by setting the baseURL to `http://127.0.0.1:3000` and navigating to `/login` in your tests, Playwright will run the test using `http://127.0.0.1:3000/login`. +When using [`method: Page.goto`], [`method: Page.route`], [`method: Page.waitForURL`], [`method: Page.waitForRequest`], or [`method: Page.waitForResponse`] it takes the base URL in consideration by using the [`URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor for building the corresponding URL. For Example, by setting the baseURL to `http://localhost:3000` and navigating to `/login` in your tests, Playwright will run the test using `http://localhost:3000/login`. ```js title="playwright.config.ts" import { defineConfig } from '@playwright/test'; @@ -74,11 +74,11 @@ export default defineConfig({ // Run your local dev server before starting the tests webServer: { command: 'npm run start', - url: 'http://127.0.0.1:3000', + url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, }, use: { - baseURL: 'http://127.0.0.1:3000', + baseURL: 'http://localhost:3000', }, }); ``` @@ -89,7 +89,7 @@ Now you can use a relative path when navigating the page: import { test } from '@playwright/test'; test('test', async ({ page }) => { - // This will navigate to http://127.0.0.1:3000/login + // This will navigate to http://localhost:3000/login await page.goto('./login'); }); ``` @@ -106,19 +106,19 @@ export default defineConfig({ webServer: [ { command: 'npm run start', - url: 'http://127.0.0.1:3000', + url: 'http://localhost:3000', timeout: 120 * 1000, reuseExistingServer: !process.env.CI, }, { command: 'npm run backend', - url: 'http://127.0.0.1:3333', + url: 'http://localhost:3333', timeout: 120 * 1000, reuseExistingServer: !process.env.CI, } ], use: { - baseURL: 'http://127.0.0.1:3000', + baseURL: 'http://localhost:3000', }, }); ``` diff --git a/docs/src/touch-events.md b/docs/src/touch-events.md index a1d394dc62d42..69e90fb71466e 100644 --- a/docs/src/touch-events.md +++ b/docs/src/touch-events.md @@ -1,19 +1,13 @@ --- id: touch-events -title: "Emulating touch events" +title: "Touch events (legacy)" --- ## Introduction -Mobile web sites may listen to [touch events](https://developer.mozilla.org/en-US/docs/Web/API/Touch_events) and react to user touch gestures such as swipe, pinch, tap etc. To test this functionality you can manually generate [TouchEvent]s in the page context using [`method: Locator.evaluate`]. +Web applications that handle legacy [touch events](https://developer.mozilla.org/en-US/docs/Web/API/Touch_events) to respond to gestures like swipe, pinch, and tap can be tested by manually dispatching [TouchEvent](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent)s to the page. The examples below demonstrate how to use [`method: Locator.dispatchEvent`] and pass [Touch](https://developer.mozilla.org/en-US/docs/Web/API/Touch) points as arguments. -If your web application relies on [pointer events](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events) instead of touch events, you can use [`method: Locator.click`] and raw [`Mouse`] events to simulate a single-finger touch, and this will trigger all the same pointer events. - -### Dispatching TouchEvent - -You can dispatch touch events to the page using [`method: Locator.dispatchEvent`]. [Touch](https://developer.mozilla.org/en-US/docs/Web/API/Touch) points can be passed as arguments, see examples below. - -#### Emulating pan gesture +### Emulating pan gesture In the example below, we emulate pan gesture that is expected to move the map. The app under test only uses `clientX/clientY` coordinates of the touch point, so we initialize just that. In a more complex scenario you may need to also set `pageX/pageY/screenX/screenY`, if your app needs them. @@ -69,7 +63,247 @@ test(`pan gesture to move the map`, async ({ page }) => { }); ``` -#### Emulating pinch gesture +```csharp +using Microsoft.Playwright; +using System.Collections.Generic; +using System.Threading.Tasks; + +public class TouchEvents +{ + public static async Task Main(string[] args) + { + using var playwright = await Playwright.CreateAsync(); + var browser = await playwright.Chromium.LaunchAsync(); + var context = await browser.NewContextAsync(playwright.Devices["Pixel 7"]); + var page = await context.NewPageAsync(); + + await page.GotoAsync( + "https://www.google.com/maps/place/@37.4117722,-122.0713234,15z", + new PageGotoOptions { WaitUntil = WaitUntilState.Commit } + ); + await page.GetByRole(AriaRole.Button, new PageGetByRoleOptions { Name = "Keep using web" }).ClickAsync(); + await page.GetByRole(AriaRole.Button, new PageGetByRoleOptions { Name = "Keep using web" }) + .WaitForAsync(new LocatorWaitForOptions { State = WaitForSelectorState.Hidden }); + + var met = page.Locator("[data-test-id='met']"); + for (int i = 0; i < 5; i++) + { + await Pan(met, 200, 100); + } + await page.ScreenshotAsync(new PageScreenshotOptions { Path = "screenshot.png" }); + } + + public static async Task Pan(ILocator locator, int deltaX, int deltaY, int steps = 5) + { + var bounds = await locator.BoundingBoxAsync(); + double centerX = bounds.X + bounds.Width / 2; + double centerY = bounds.Y + bounds.Height / 2; + + var touches = new List> + { + new Dictionary + { + { "identifier", 0 }, + { "clientX", centerX }, + { "clientY", centerY } + } + }; + await locator.DispatchEventAsync("touchstart", new { touches, changedTouches = touches, targetTouches = touches }); + + for (int i = 1; i <= steps; i++) + { + touches = new List> + { + new Dictionary + { + { "identifier", 0 }, + { "clientX", centerX + deltaX * i / steps }, + { "clientY", centerY + deltaY * i / steps } + } + }; + await locator.DispatchEventAsync("touchmove", new { touches, changedTouches = touches, targetTouches = touches }); + } + + await locator.DispatchEventAsync("touchend"); + } +} +``` + +```java +import com.microsoft.playwright.*; +import com.microsoft.playwright.options.*; + +public class TouchEvents { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + Browser browser = playwright.chromium().launch(); + BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setViewportSize(412, 839) + .setDeviceScaleFactor(2.625) + .setUserAgent("Mozilla/5.0 (Linux; Android 12; Pixel 7 Build/SP1A.210812.015) AppleWebKit/537.36" + + " (KHTML, like Gecko) Chrome/94.0.4606.71 Mobile Safari/537.36") + .setHasTouch(true) + .setIsMobile(true) + ); + Page page = context.newPage(); + + page.navigate("https://www.google.com/maps/place/@37.4117722,-122.0713234,15z", new Page.NavigateOptions().setWaitUntil(WaitUntilState.COMMIT)); + page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Keep using web")).click(); + page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Keep using web")).waitFor( + new Locator.WaitForOptions().setState(WaitForSelectorState.HIDDEN)); + + Locator met = page.locator("[data-test-id='met']"); + for (int i = 0; i < 5; i++) { + pan(met, 200, 100); + } + page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshot.png"))); + } + } + + public static void pan(Locator locator, int deltaX, int deltaY) { + pan(locator, deltaX, deltaY, 5); + } + + public static void pan(Locator locator, int deltaX, int deltaY, int steps) { + BoundingBox bounds = locator.boundingBox(); + double centerX = bounds.x + bounds.width / 2; + double centerY = bounds.y + bounds.height / 2; + + List> touches = List.of(Map.of( + "identifier", 0, + "clientX", centerX, + "clientY", centerY + )); + locator.dispatchEvent("touchstart", Map.of( + "touches", touches, + "changedTouches", touches, + "targetTouches", touches + )); + + for (int i = 1; i <= steps; i++) { + touches = List.of(Map.of( + "identifier", 0, + "clientX", centerX + deltaX * i / steps, + "clientY", centerY + deltaY * i / steps + )); + locator.dispatchEvent("touchmove", Map.of( + "touches", touches, + "changedTouches", touches, + "targetTouches", touches + )); + } + + locator.dispatchEvent("touchend"); + } +} +``` + +```python sync +from playwright.sync_api import sync_playwright, expect + +def pan(locator, deltaX=0, deltaY=0, steps=5): + bounds = locator.bounding_box() + centerX = bounds['x'] + bounds['width'] / 2 + centerY = bounds['y'] + bounds['height'] / 2 + + touches = [{ + 'identifier': 0, + 'clientX': centerX, + 'clientY': centerY, + }] + locator.dispatch_event('touchstart', { + 'touches': touches, + 'changedTouches': touches, + 'targetTouches': touches + }) + + for i in range(1, steps + 1): + touches = [{ + 'identifier': 0, + 'clientX': centerX + deltaX * i / steps, + 'clientY': centerY + deltaY * i / steps, + }] + locator.dispatch_event('touchmove', { + 'touches': touches, + 'changedTouches': touches, + 'targetTouches': touches + }) + + locator.dispatch_event('touchend') + +def test_pan_gesture_to_move_the_map(page): + page.goto('https://www.google.com/maps/place/@37.4117722,-122.0713234,15z', wait_until='commit') + page.get_by_role('button', name='Keep using web').click() + expect(page.get_by_role('button', name='Keep using web')).not_to_be_visible() + met = page.locator('[data-test-id="met"]') + for _ in range(5): + pan(met, 200, 100) + page.screenshot(path="screenshot.png") + +with sync_playwright() as p: + browser = p.chromium.launch() + context = browser.new_context(**p.devices['Pixel 7']) + page = context.new_page() + test_pan_gesture_to_move_the_map(page) + browser.close() +``` + +```python async +from playwright.async_api import async_playwright, expect + +async def pan(locator, deltaX=0, deltaY=0, steps=5): + bounds = await locator.bounding_box() + centerX = bounds['x'] + bounds['width'] / 2 + centerY = bounds['y'] + bounds['height'] / 2 + + touches = [{ + 'identifier': 0, + 'clientX': centerX, + 'clientY': centerY, + }] + await locator.dispatch_event('touchstart', { + 'touches': touches, + 'changedTouches': touches, + 'targetTouches': touches + }) + + for i in range(1, steps + 1): + touches = [{ + 'identifier': 0, + 'clientX': centerX + deltaX * i / steps, + 'clientY': centerY + deltaY * i / steps, + }] + await locator.dispatch_event('touchmove', { + 'touches': touches, + 'changedTouches': touches, + 'targetTouches': touches + }) + + await locator.dispatch_event('touchend') + +async def test_pan_gesture_to_move_the_map(page): + await page.goto('https://www.google.com/maps/place/@37.4117722,-122.0713234,15z', wait_until='commit') + await page.get_by_role('button', name='Keep using web').click() + await expect(page.get_by_role('button', name='Keep using web')).not_to_be_visible() + met = page.locator('[data-test-id="met"]') + for _ in range(5): + await pan(met, 200, 100) + await page.screenshot(path="screenshot.png") + +async def main(): + async with async_playwright() as p: + browser = await p.chromium.launch() + context = await browser.new_context(**p.devices['Pixel 7']) + page = await context.new_page() + await test_pan_gesture_to_move_the_map(page) + await browser.close() + +import asyncio +asyncio.run(main()) +``` + + +### Emulating pinch gesture In the example below, we emulate pinch gesture, i.e. two touch points moving closer to each other. It is expected to zoom out the map. The app under test only uses `clientX/clientY` coordinates of touch points, so we initialize just that. In a more complex scenario you may need to also set `pageX/pageY/screenX/screenY`, if your app needs them. @@ -142,3 +376,285 @@ test(`pinch in gesture to zoom out the map`, async ({ page }) => { await expect(met).toHaveScreenshot(); }); ``` + +```csharp +using Microsoft.Playwright; +using System.Collections.Generic; +using System.Threading.Tasks; + +public class TouchEvents +{ + public static async Task Pinch(ILocator locator, int deltaX = 50, int steps = 5, string direction = "in") + { + var bounds = await locator.BoundingBoxAsync(); + double centerX = bounds.X + bounds.Width / 2; + double centerY = bounds.Y + bounds.Height / 2; + double stepDeltaX = deltaX / (steps + 1.0); + + var touches = new List> + { + new Dictionary + { + { "identifier", 0 }, + { "clientX", centerX - (direction == "in" ? deltaX : stepDeltaX) }, + { "clientY", centerY } + }, + new Dictionary + { + { "identifier", 1 }, + { "clientX", centerX + (direction == "in" ? deltaX : stepDeltaX) }, + { "clientY", centerY } + } + }; + await locator.DispatchEventAsync("touchstart", new { touches, changedTouches = touches, targetTouches = touches }); + + for (int i = 1; i <= steps; i++) + { + double offset = direction == "in" ? (deltaX - i * stepDeltaX) : (stepDeltaX * (i + 1)); + touches = new List> + { + new Dictionary + { + { "identifier", 0 }, + { "clientX", centerX - offset }, + { "clientY", centerY } + }, + new Dictionary + { + { "identifier", 1 }, + { "clientX", centerX + offset }, + { "clientY", centerY } + } + }; + await locator.DispatchEventAsync("touchmove", new { touches, changedTouches = touches, targetTouches = touches }); + } + + await locator.DispatchEventAsync("touchend", new { touches = new List(), changedTouches = new List(), targetTouches = new List() }); + } + + public static async Task TestPinchInGestureToZoomOutTheMap(IPage page) + { + await page.GotoAsync("https://www.google.com/maps/place/@37.4117722,-122.0713234,15z", new PageGotoOptions { WaitUntil = WaitUntilState.Commit }); + await page.GetByRole(AriaRole.Button, new PageGetByRoleOptions { Name = "Keep using web" }).ClickAsync(); + await page.GetByRole(AriaRole.Button, new PageGetByRoleOptions { Name = "Keep using web" }).WaitForAsync(new LocatorWaitForOptions { State = WaitForSelectorState.Hidden }); + + var met = page.Locator("[data-test-id='met']"); + for (int i = 0; i < 5; i++) + { + await Pinch(met, 40, 5, "in"); + } + await page.ScreenshotAsync(new PageScreenshotOptions { Path = "screenshot.png" }); + } +} +``` + +```java +import com.microsoft.playwright.*; +import com.microsoft.playwright.options.*; + +public class TouchEvents { + public static void main(String[] args) { + try (Playwright playwright = Playwright.create()) { + Browser browser = playwright.chromium().launch(); + BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setViewportSize(412, 839) + .setDeviceScaleFactor(2.625) + .setUserAgent("Mozilla/5.0 (Linux; Android 12; Pixel 7 Build/SP1A.210812.015) AppleWebKit/537.36" + + " (KHTML, like Gecko) Chrome/94.0.4606.71 Mobile Safari/537.36") + .setHasTouch(true) + .setIsMobile(true) + ); + Page page = context.newPage(); + + page.navigate("https://www.google.com/maps/place/@37.4117722,-122.0713234,15z", new Page.NavigateOptions().setWaitUntil(WaitUntilState.COMMIT)); + page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Keep using web")).click(); + page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Keep using web")).waitFor( + new Locator.WaitForOptions().setState(WaitForSelectorState.HIDDEN)); + + Locator met = page.locator("[data-test-id='met']"); + for (int i = 0; i < 5; i++) { + pinch(met, 40, "in"); + } + page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshot.png"))); + } + } + + public static void pinch(Locator locator, int deltaX, String direction) { + pinch(locator, deltaX, direction, 5); + } + + public static void pinch(Locator locator, int deltaX, String direction, int steps) { + BoundingBox bounds = locator.boundingBox(); + double centerX = bounds.x + bounds.width / 2; + double centerY = bounds.y + bounds.height / 2; + double stepDeltaX = deltaX / (steps + 1.0); + + List> touches = List.of( + Map.of("identifier", 0, "clientX", centerX - (direction.equals("in") ? deltaX : stepDeltaX), "clientY", centerY), + Map.of("identifier", 1, "clientX", centerX + (direction.equals("in") ? deltaX : stepDeltaX), "clientY", centerY) + ); + locator.dispatchEvent("touchstart", Map.of("touches", touches, "changedTouches", touches, "targetTouches", touches)); + + for (int i = 1; i <= steps; i++) { + double offset = direction.equals("in") ? (deltaX - i * stepDeltaX) : (stepDeltaX * (i + 1)); + touches = List.of( + Map.of("identifier", 0, "clientX", centerX - offset, "clientY", centerY), + Map.of("identifier", 1, "clientX", centerX + offset, "clientY", centerY) + ); + locator.dispatchEvent("touchmove", Map.of("touches", touches, "changedTouches", touches, "targetTouches", touches)); + } + + locator.dispatchEvent("touchend", Map.of("touches", List.of(), "changedTouches", List.of(), "targetTouches", List.of())); + } +} +``` + +```python async +from playwright.async_api import async_playwright, expect + +async def pinch(locator, arg): + bounds = await locator.bounding_box() + centerX = bounds['x'] + bounds['width'] / 2 + centerY = bounds['y'] + bounds['height'] / 2 + + deltaX = arg.get('deltaX', 50) + steps = arg.get('steps', 5) + stepDeltaX = deltaX / (steps + 1) + + touches = [ + { + 'identifier': 0, + 'clientX': centerX - (deltaX if arg.get('direction') == 'in' else stepDeltaX), + 'clientY': centerY, + }, + { + 'identifier': 1, + 'clientX': centerX + (deltaX if arg.get('direction') == 'in' else stepDeltaX), + 'clientY': centerY, + }, + ] + await locator.dispatch_event('touchstart', { + 'touches': touches, + 'changedTouches': touches, + 'targetTouches': touches + }) + + for i in range(1, steps + 1): + offset = deltaX - i * stepDeltaX if arg.get('direction') == 'in' else stepDeltaX * (i + 1) + touches = [ + { + 'identifier': 0, + 'clientX': centerX - offset, + 'clientY': centerY, + }, + { + 'identifier': 1, + 'clientX': centerX + offset, + 'clientY': centerY, + }, + ] + await locator.dispatch_event('touchmove', { + 'touches': touches, + 'changedTouches': touches, + 'targetTouches': touches + }) + + await locator.dispatch_event('touchend', { + 'touches': [], + 'changedTouches': [], + 'targetTouches': [] + }) + +async def test_pinch_in_gesture_to_zoom_out_the_map(page): + await page.goto('https://www.google.com/maps/place/@37.4117722,-122.0713234,15z', wait_until='commit') + await page.get_by_role('button', name='Keep using web').click() + await expect(page.get_by_role('button', name='Keep using web')).not_to_be_visible() + met = page.locator('[data-test-id="met"]') + for _ in range(5): + await pinch(met, {'deltaX': 40, 'direction': 'in'}) + await page.screenshot(path="screenshot.png") + +async def main(): + async with async_playwright() as p: + browser = await p.chromium.launch() + context = await browser.new_context(**p.devices['Pixel 7']) + page = await context.new_page() + await test_pinch_in_gesture_to_zoom_out_the_map(page) + await browser.close() + +import asyncio +asyncio.run(main()) +``` + +```python sync +from playwright.sync_api import sync_playwright, expect + +def pinch(locator, arg): + bounds = locator.bounding_box() + centerX = bounds['x'] + bounds['width'] / 2 + centerY = bounds['y'] + bounds['height'] / 2 + + deltaX = arg.get('deltaX', 50) + steps = arg.get('steps', 5) + stepDeltaX = deltaX / (steps + 1) + + touches = [ + { + 'identifier': 0, + 'clientX': centerX - (deltaX if arg.get('direction') == 'in' else stepDeltaX), + 'clientY': centerY, + }, + { + 'identifier': 1, + 'clientX': centerX + (deltaX if arg.get('direction') == 'in' else stepDeltaX), + 'clientY': centerY, + }, + ] + locator.dispatch_event('touchstart', { + 'touches': touches, + 'changedTouches': touches, + 'targetTouches': touches + }) + + for i in range(1, steps + 1): + offset = deltaX - i * stepDeltaX if arg.get('direction') == 'in' else stepDeltaX * (i + 1) + touches = [ + { + 'identifier': 0, + 'clientX': centerX - offset, + 'clientY': centerY, + }, + { + 'identifier': 1, + 'clientX': centerX + offset, + 'clientY': centerY, + }, + ] + locator.dispatch_event('touchmove', { + 'touches': touches, + 'changedTouches': touches, + 'targetTouches': touches + }) + + locator.dispatch_event('touchend', { + 'touches': [], + 'changedTouches': [], + 'targetTouches': [] + }) + +def test_pinch_in_gesture_to_zoom_out_the_map(page): + page.goto('https://www.google.com/maps/place/@37.4117722,-122.0713234,15z', wait_until='commit') + page.get_by_role('button', name='Keep using web').click() + expect(page.get_by_role('button', name='Keep using web')).not_to_be_visible() + met = page.locator('[data-test-id="met"]') + for _ in range(5): + pinch(met, {'deltaX': 40, 'direction': 'in'}) + page.screenshot(path="screenshot.png") + +with sync_playwright() as p: + browser = p.chromium.launch() + context = browser.new_context(**p.devices['Pixel 7']) + page = context.new_page() + test_pinch_in_gesture_to_zoom_out_the_map(page) + browser.close() +``` \ No newline at end of file diff --git a/eslint-react.config.mjs b/eslint-react.config.mjs new file mode 100644 index 0000000000000..83ee9934879f0 --- /dev/null +++ b/eslint-react.config.mjs @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { fixupConfigRules } from '@eslint/compat'; +import { FlatCompat } from '@eslint/eslintrc'; +import js from '@eslint/js'; +import typescriptEslint from '@typescript-eslint/eslint-plugin'; +import tsParser from '@typescript-eslint/parser'; +import notice from 'eslint-plugin-notice'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import stylistic from '@stylistic/eslint-plugin'; +import { baseRules } from './eslint.config.mjs'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all +}); + +const baseConfig = fixupConfigRules(compat.extends('plugin:react/recommended', 'plugin:react-hooks/recommended')); + +const plugins = { + '@stylistic': stylistic, + '@typescript-eslint': typescriptEslint, + notice, +}; + +const ignores = [ + '.github/', + '*.js', + '**/.cache/', + '**/*.d.ts', + '**/dist/**', + 'index.d.ts', + 'node_modules/', + 'output/', + 'packages/*/lib/', + 'test-results/', + 'tests/', + 'utils/', +]; + +export default [ + { ignores }, + { + plugins, + settings: { + react: { version: 'detect' }, + } + }, + ...baseConfig, + packageSection('html-reporter'), + packageSection('recorder'), + packageSection('trace-viewer'), +]; + +function packageSection(packageName) { + return { + files: [ + `packages/${packageName}/src/**/*.ts`, + `packages/${packageName}/src/**/*.tsx`, + `packages/web/src/**/*.ts`, + `packages/web/src/**/*.tsx`, + ], + languageOptions: { + parser: tsParser, + ecmaVersion: 9, + sourceType: 'module', + parserOptions: { + project: path.join(__dirname, 'packages', packageName, 'tsconfig.json'), + }, + }, + rules: { + ...baseRules, + 'no-console': 2, + } + }; +} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000000000..41799d05f9745 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,292 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import typescriptEslint from '@typescript-eslint/eslint-plugin'; +import tsParser from '@typescript-eslint/parser'; +import notice from 'eslint-plugin-notice'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import stylistic from '@stylistic/eslint-plugin'; +import importRules from 'eslint-plugin-import'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const plugins = { + '@stylistic': stylistic, + '@typescript-eslint': typescriptEslint, + notice, + import: importRules, +}; + +const ignores = [ + '.github/', + '*.js', + '**/.cache/', + '**/*.d.ts', + 'index.d.ts', + 'node_modules/', + 'output/', + 'packages/*/lib/', + 'packages/html-reporter/**', + 'packages/playwright-core/src/generated/*', + 'packages/playwright-core/src/third_party/', + 'packages/playwright-core/types/*', + 'packages/playwright-ct-core/src/generated/*', + 'packages/recorder/**', + 'packages/trace-viewer/**', + 'packages/web/**', + 'test-results/', + 'tests/assets/', + 'tests/components/', + 'tests/installation/fixture-scripts/', + 'tests/third_party/', + 'utils/', +]; + +export const baseRules = { + '@typescript-eslint/no-unused-vars': [2, { args: 'none', caughtErrors: 'none' }], + + /** + * Enforced rules + */ + // syntax preferences + 'object-curly-spacing': ['error', 'always'], + 'quotes': [2, 'single', { + 'avoidEscape': true, + 'allowTemplateLiterals': true + }], + 'jsx-quotes': [2, 'prefer-single'], + 'no-extra-semi': 2, + '@stylistic/semi': [2], + 'comma-style': [2, 'last'], + 'wrap-iife': [2, 'inside'], + 'spaced-comment': [2, 'always', { + 'markers': ['*'] + }], + 'eqeqeq': [2], + 'accessor-pairs': [2, { + 'getWithoutSet': false, + 'setWithoutGet': false + }], + 'brace-style': [2, '1tbs', { 'allowSingleLine': true }], + 'curly': [2, 'multi-or-nest', 'consistent'], + 'new-parens': 2, + 'arrow-parens': [2, 'as-needed'], + 'prefer-const': 2, + 'quote-props': [2, 'consistent'], + 'nonblock-statement-body-position': [2, 'below'], + + // anti-patterns + 'no-var': 2, + 'no-with': 2, + 'no-multi-str': 2, + 'no-caller': 2, + 'no-implied-eval': 2, + 'no-labels': 2, + 'no-new-object': 2, + 'no-octal-escape': 2, + 'no-self-compare': 2, + 'no-shadow-restricted-names': 2, + 'no-cond-assign': 2, + 'no-debugger': 2, + 'no-dupe-keys': 2, + 'no-duplicate-case': 2, + 'no-empty-character-class': 2, + 'no-unreachable': 2, + 'no-unsafe-negation': 2, + 'radix': 2, + 'valid-typeof': 2, + 'no-implicit-globals': [2], + 'no-unused-expressions': [2, { 'allowShortCircuit': true, 'allowTernary': true, 'allowTaggedTemplates': true }], + 'no-proto': 2, + + // es2015 features + 'require-yield': 2, + 'template-curly-spacing': [2, 'never'], + + // spacing details + 'space-infix-ops': 2, + 'space-in-parens': [2, 'never'], + 'array-bracket-spacing': [2, 'never'], + 'comma-spacing': [2, { 'before': false, 'after': true }], + 'keyword-spacing': [2, 'always'], + 'space-before-function-paren': [2, { + 'anonymous': 'never', + 'named': 'never', + 'asyncArrow': 'always' + }], + 'no-whitespace-before-property': 2, + 'keyword-spacing': [2, { + 'overrides': { + 'if': { 'after': true }, + 'else': { 'after': true }, + 'for': { 'after': true }, + 'while': { 'after': true }, + 'do': { 'after': true }, + 'switch': { 'after': true }, + 'return': { 'after': true } + } + }], + 'arrow-spacing': [2, { + 'after': true, + 'before': true + }], + '@stylistic/func-call-spacing': 2, + '@stylistic/type-annotation-spacing': 2, + + // file whitespace + 'no-multiple-empty-lines': [2, { 'max': 2, 'maxEOF': 0 }], + 'no-mixed-spaces-and-tabs': 2, + 'no-trailing-spaces': 2, + 'linebreak-style': [process.platform === 'win32' ? 0 : 2, 'unix'], + 'indent': [2, 2, { 'SwitchCase': 1, 'CallExpression': { 'arguments': 2 }, 'MemberExpression': 2 }], + 'key-spacing': [2, { + 'beforeColon': false + }], + 'eol-last': 2, + + // copyright + 'notice/notice': [2, { + 'mustMatch': 'Copyright', + 'templateFile': path.join(__dirname, 'utils', 'copyright.js'), + }], + + // react + 'react/react-in-jsx-scope': 0 +}; + +const noFloatingPromisesRules = { + '@typescript-eslint/no-floating-promises': 'error', +}; + +const noBooleanCompareRules = { + '@typescript-eslint/no-unnecessary-boolean-literal-compare': 2, +}; + +const noWebGlobalsRules = { + 'no-restricted-globals': [ + 'error', + { 'name': 'window' }, + { 'name': 'document' }, + { 'name': 'globalThis' }, + ], +}; + +const noNodeGlobalsRules = { + 'no-restricted-globals': [ + 'error', + { 'name': 'process' }, + ], +}; + +const importOrderRules = { + 'import/order': [2, { + 'groups': ['builtin', 'external', 'internal', ['parent', 'sibling'], 'index', 'type'], + 'newlines-between': 'always', + }], + 'import/consistent-type-specifier-style': [2, 'prefer-top-level'] +}; + +const languageOptions = { + parser: tsParser, + ecmaVersion: 9, + sourceType: 'module', +}; + +const languageOptionsWithTsConfig = { + parser: tsParser, + ecmaVersion: 9, + sourceType: 'module', + parserOptions: { + project: path.join(__dirname, 'tsconfig.json'), + }, +}; + +export default [{ + ignores, +}, { + files: ['**/*.ts'], + plugins, + languageOptions, + rules: baseRules, +}, { + files: ['packages/**/*.ts'], + languageOptions: languageOptionsWithTsConfig, + rules: { + 'no-console': 2, + 'no-restricted-properties': [2, { + 'object': 'process', + 'property': 'exit', + 'message': 'Please use gracefullyProcessExitDoNotHang function to exit the process.', + }], + } +}, { + files: [ + 'packages/**/*.ts', + ], + rules: { + ...importOrderRules + }, +}, { + files: ['packages/playwright/**/*.ts'], + rules: { + ...noFloatingPromisesRules, + } +}, { + files: ['packages/playwright/src/reporters/**/*.ts'], + languageOptions: languageOptionsWithTsConfig, + rules: { + 'no-console': 'off' + } +}, { + files: [ + 'packages/playwright-core/src/server/injected/**/*.ts', + 'packages/playwright-core/src/server/isomorphic/**/*.ts', + 'packages/playwright-core/src/utils/isomorphic/**/*.ts', + ], + languageOptions: languageOptionsWithTsConfig, + rules: { + ...noWebGlobalsRules, + ...noFloatingPromisesRules, + ...noBooleanCompareRules, + } +}, { + files: [ + 'packages/playwright-core/src/client/**/*.ts', + 'packages/playwright-core/src/protocol/**/*.ts', + 'packages/playwright-core/src/utils/**/*.ts', + ], + languageOptions: languageOptionsWithTsConfig, + rules: { + ...noNodeGlobalsRules, + ...noFloatingPromisesRules, + ...noBooleanCompareRules, + } +}, { + files: ['tests/**/*.spec.js', 'tests/**/*.ts'], + languageOptions: { + parser: tsParser, + ecmaVersion: 9, + sourceType: 'module', + parserOptions: { + project: path.join(__dirname, 'tests', 'tsconfig.json'), + }, + }, + rules: { + ...noFloatingPromisesRules, + } +}]; diff --git a/examples/todomvc/playwright.config.ts b/examples/todomvc/playwright.config.ts index 3d76370d4d30c..831aa9035595b 100644 --- a/examples/todomvc/playwright.config.ts +++ b/examples/todomvc/playwright.config.ts @@ -12,6 +12,8 @@ export default defineConfig({ /* Maximum time one test can run for. */ timeout: 15_000, + captureGitInfo: { commit: true, diff: true }, + expect: { /** diff --git a/package-lock.json b/package-lock.json index 411ef13b62846..04e4272a09914 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "playwright-internal", - "version": "1.50.0-next", + "version": "1.51.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "playwright-internal", - "version": "1.50.0-next", + "version": "1.51.1", "license": "Apache-2.0", "workspaces": [ "packages/*" @@ -23,6 +23,10 @@ "@babel/plugin-transform-optional-chaining": "^7.23.4", "@babel/plugin-transform-typescript": "^7.23.6", "@babel/preset-react": "^7.23.3", + "@eslint/compat": "^1.2.6", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "^9.19.0", + "@stylistic/eslint-plugin": "^3.0.1", "@types/babel__core": "^7.20.2", "@types/codemirror": "^5.60.7", "@types/formidable": "^2.0.4", @@ -32,9 +36,9 @@ "@types/react-dom": "^18.0.5", "@types/ws": "^8.5.3", "@types/xml2js": "^0.4.9", - "@typescript-eslint/eslint-plugin": "^7.15.0", - "@typescript-eslint/parser": "^7.15.0", - "@typescript-eslint/utils": "^7.15.0", + "@typescript-eslint/eslint-plugin": "^8.23.0", + "@typescript-eslint/parser": "^8.23.0", + "@typescript-eslint/utils": "^8.23.0", "@vitejs/plugin-basic-ssl": "^1.1.0", "@vitejs/plugin-react": "^4.2.1", "@zip.js/zip.js": "^2.7.29", @@ -46,79 +50,108 @@ "cross-env": "^7.0.3", "dotenv": "^16.4.5", "electron": "^30.1.2", - "esbuild": "^0.18.11", - "eslint": "^8.55.0", - "eslint-plugin-internal-playwright": "file:utils/eslint-plugin-internal-playwright", - "eslint-plugin-notice": "^0.9.10", - "eslint-plugin-react": "^7.35.0", - "eslint-plugin-react-hooks": "^4.6.2", + "esbuild": "^0.25.0", + "eslint": "^9.19.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-notice": "^1.0.0", + "eslint-plugin-react": "^7.37.4", + "eslint-plugin-react-hooks": "^5.1.0", "formidable": "^2.1.1", "immutable": "^4.3.7", "license-checker": "^25.0.1", + "markdown-to-jsx": "^7.7.3", "mime": "^3.0.0", "node-stream-zip": "^1.15.0", "react": "^18.1.0", "react-dom": "^18.1.0", "ssim.js": "^3.5.0", - "typescript": "^5.7.2", - "vite": "^5.4.6", + "typescript": "^5.7.3", + "vite": "^6.1.0", "ws": "^8.17.1", "xml2js": "^0.5.0", - "yaml": "^2.6.0" + "yaml": "2.6.0" }, "engines": { "node": ">=18" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "node_modules/@actions/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", + "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "MIT", + "dependencies": { + "@actions/exec": "^1.1.1", + "@actions/http-client": "^2.0.1" } }, - "node_modules/@actions/core": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz", - "integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==", + "node_modules/@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", "dev": true, + "license": "MIT", "dependencies": { - "@actions/http-client": "^2.0.1", - "uuid": "^8.3.2" + "@actions/io": "^1.0.1" } }, "node_modules/@actions/http-client": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.0.tgz", - "integrity": "sha512-q+epW0trjVUUHboliPb4UF9g2msf+w61b32tAkFEwL/IwP0DQWgbCMM0Hbe3e3WXSKz5VcUXbzJQgy8Hkra/Lg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", + "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", "dev": true, + "license": "MIT", "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, + "node_modules/@actions/io": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", + "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.33.1.tgz", + "integrity": "sha512-VrlbxiAdVRGuKP2UQlCnsShDHJKWepzvfRCkZMpU+oaUdKLpOfmylLMRojGrAgebV+kDtPjewCVP0laHXg+vsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + } + }, "node_modules/@babel/cli": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.23.4.tgz", - "integrity": "sha512-j3luA9xGKCXVyCa5R7lJvOMM+Kc2JEnAEIgz2ggtjQ/j5YUVgfsg/WsG95bbsgq7YLHuiCOzMnoSasuY16qiCw==", + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.26.4.tgz", + "integrity": "sha512-+mORf3ezU3p3qr+82WvJSnQNE1GAYeoCfEv4fik6B5/2cvKZ75AX8oawWQdXtM9MmndooQj15Jr9kelRFWsuRw==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "commander": "^4.0.1", + "@jridgewell/trace-mapping": "^0.3.25", + "commander": "^6.2.0", "convert-source-map": "^2.0.0", "fs-readdir-recursive": "^1.1.0", "glob": "^7.2.0", @@ -134,47 +167,51 @@ }, "optionalDependencies": { "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", - "chokidar": "^3.4.0" + "chokidar": "^3.6.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", + "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", - "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.9.tgz", + "integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.7", - "@babel/parser": "^7.23.6", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.9", + "@babel/types": "^7.26.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -190,39 +227,43 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz", + "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -231,19 +272,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.7.tgz", - "integrity": "sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz", + "integrity": "sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.26.9", "semver": "^6.3.1" }, "engines": { @@ -253,70 +293,42 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.0" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.15" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -326,34 +338,37 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", - "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", + "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.22.15", - "@babel/helper-optimise-call-expression": "^7.22.5" + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -362,35 +377,15 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -415,46 +410,34 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", - "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.9.tgz", + "integrity": "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==", + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", - "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz", + "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.3" + "@babel/types": "^7.26.9" }, "bin": { "parser": "bin/babel-parser.js" @@ -463,25 +446,14 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -490,49 +462,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -542,13 +479,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", - "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -558,13 +496,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", - "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -574,13 +512,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", - "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -590,14 +528,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", - "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5" + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -607,13 +545,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", - "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "version": "7.26.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz", + "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -623,14 +561,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", - "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -640,12 +578,13 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz", - "integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", + "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -655,16 +594,17 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", - "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", + "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.23.3", - "@babel/types": "^7.23.4" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -674,12 +614,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", - "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz", + "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.22.5" + "@babel/plugin-transform-react-jsx": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -689,11 +630,12 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", - "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", + "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -703,11 +645,12 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", - "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", + "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -717,13 +660,14 @@ } }, "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz", - "integrity": "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz", + "integrity": "sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -733,15 +677,17 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz", - "integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz", + "integrity": "sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.23.6", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-typescript": "^7.23.3" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-syntax-typescript": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -751,17 +697,18 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz", - "integrity": "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz", + "integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.15", - "@babel/plugin-transform-react-display-name": "^7.23.3", - "@babel/plugin-transform-react-jsx": "^7.22.15", - "@babel/plugin-transform-react-jsx-development": "^7.22.5", - "@babel/plugin-transform-react-pure-annotations": "^7.23.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-react-display-name": "^7.25.9", + "@babel/plugin-transform-react-jsx": "^7.25.9", + "@babel/plugin-transform-react-jsx-development": "^7.25.9", + "@babel/plugin-transform-react-pure-annotations": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -771,10 +718,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", - "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz", + "integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==", "dev": true, + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -783,31 +731,30 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", + "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", - "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz", + "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -816,9 +763,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", - "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz", + "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -833,6 +780,7 @@ "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", @@ -850,406 +798,529 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", + "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", "cpu": [ "ppc64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", + "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", + "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", + "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", + "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", + "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", + "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", + "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", + "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", + "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", + "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", + "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", "cpu": [ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", + "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", "cpu": [ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", + "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", + "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", + "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", + "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", + "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", + "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", + "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", + "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", + "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", + "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", + "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", + "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/compat": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.6.tgz", + "integrity": "sha512-k7HNCqApoDHM6XzT30zGoETj+D+uUcZUb+IVAJmar3u6bvHf7hhHJcWx09QHj4/a2qrKZMWU0E16tvkiAdv06Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.10.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz", + "integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -1257,113 +1328,118 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@eslint/js": { + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz", + "integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", "engines": { - "node": "*" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", + "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.10.0", + "levn": "^0.4.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", + "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@fastify/busboy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", - "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, + "license": "Apache-2.0", "engines": { - "node": ">=10.10.0" + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "Apache-2.0", "engines": { - "node": "*" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@humanwhocodes/module-importer": { @@ -1371,6 +1447,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -1379,37 +1456,48 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -1421,9 +1509,10 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz", - "integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1434,6 +1523,7 @@ "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/@nodelib/fs.scandir": { @@ -1441,6 +1531,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1454,6 +1545,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -1463,6 +1555,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1483,6 +1576,10 @@ "resolved": "packages/playwright-browser-webkit", "link": true }, + "node_modules/@playwright/client": { + "resolved": "packages/playwright-client", + "link": true + }, "node_modules/@playwright/experimental-ct-core": { "resolved": "packages/playwright-ct-core", "link": true @@ -1503,207 +1600,274 @@ "resolved": "packages/playwright-ct-vue", "link": true }, + "node_modules/@playwright/experimental-tools": { + "resolved": "packages/playwright-tools", + "link": true + }, "node_modules/@playwright/test": { "resolved": "packages/playwright-test", "link": true }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", - "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", + "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz", - "integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", + "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz", - "integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", + "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz", - "integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", + "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" ] }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", + "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", + "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz", - "integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", + "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz", - "integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", + "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz", - "integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", + "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz", - "integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", + "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", "cpu": [ "arm64" ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", + "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz", - "integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", + "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz", - "integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", + "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", "cpu": [ "riscv64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz", - "integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", + "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", "cpu": [ "s390x" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz", - "integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", + "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz", - "integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", + "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz", - "integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", + "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz", - "integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", + "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz", - "integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", + "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" ] }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -1711,41 +1875,24 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.0.1.tgz", - "integrity": "sha512-CGURX6Ps+TkOovK6xV+Y2rn8JKa8ZPUHPZ/NKgCxAmgBrXReavzFl8aOSCj3kQ1xqT7yGJj53hjcV/gqwDAaWA==", - "dependencies": { - "@sveltejs/vite-plugin-svelte-inspector": "^2.0.0-next.0 || ^2.0.0", - "debug": "^4.3.4", - "deepmerge": "^4.3.1", - "kleur": "^4.1.5", - "magic-string": "^0.30.5", - "svelte-hmr": "^0.15.3", - "vitefu": "^0.2.5" - }, - "engines": { - "node": "^18.0.0 || >=20" - }, - "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.0" - } - }, - "node_modules/@sveltejs/vite-plugin-svelte-inspector": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.0.0.tgz", - "integrity": "sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==", + "node_modules/@stylistic/eslint-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-3.1.0.tgz", + "integrity": "sha512-pA6VOrOqk0+S8toJYhQGv2MWpQQR0QpeUo9AhNkC49Y26nxBQ/nH1rta9bUU1rPw2fJ1zZEMV5oCX5AazT7J2g==", + "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.3.4" + "@typescript-eslint/utils": "^8.13.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" }, "engines": { - "node": "^18.0.0 || >=20" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.0", - "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.0" + "eslint": ">=8.40.0" } }, "node_modules/@szmarczak/http-timer": { @@ -1753,6 +1900,7 @@ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", "dev": true, + "license": "MIT", "dependencies": { "defer-to-connect": "^2.0.0" }, @@ -1764,6 +1912,7 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -1776,6 +1925,7 @@ "version": "7.6.8", "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } @@ -1784,15 +1934,17 @@ "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", - "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" } @@ -1802,6 +1954,7 @@ "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-cache-semantics": "*", "@types/keyv": "^3.1.4", @@ -1814,20 +1967,23 @@ "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.15.tgz", "integrity": "sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==", "dev": true, + "license": "MIT", "dependencies": { "@types/tern": "*" } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "license": "MIT" }, "node_modules/@types/formidable": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-2.0.6.tgz", "integrity": "sha512-L4HcrA05IgQyNYJj6kItuIkXrInJvsXTPC5B1i64FggWKKqSL+4hgt7asiSNva75AoLQjq29oPxFfU4GAQ6Z2w==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1836,7 +1992,8 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/immutable": { "version": "3.8.7", @@ -1844,53 +2001,82 @@ "integrity": "sha512-nsHFDX48Tl3RaP4BF47HHe5njx40Pcp+0a8CIqzJata80Fp7JzkcuGB7UhZBGjH9aA1fMEahIqvPQQNmro5YLg==", "deprecated": "This is a stub types definition for Facebook's Immutable (https://github.com/facebook/immutable-js). Facebook's Immutable provides its own type definitions, so you don't need @types/immutable installed!", "dev": true, + "license": "MIT", "dependencies": { "immutable": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/node": { - "version": "18.19.68", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.68.tgz", - "integrity": "sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==", + "version": "18.19.76", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.76.tgz", + "integrity": "sha512-yvR7Q9LdPz2vGpmpJX5LolrgRdWvB67MJKDPSgIIzpFbaf9a1j/f5DnLp5VDyHGMR0QZHlTr1afsD87QCXFHKw==", "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, "node_modules/@types/prop-types": { - "version": "15.7.11", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "dev": true + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/react": { - "version": "18.2.48", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz", - "integrity": "sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==", + "version": "18.3.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", + "integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.18", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", - "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==", + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz", + "integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==", "dev": true, - "dependencies": { - "@types/react": "*" + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" } }, "node_modules/@types/responselike": { @@ -1898,30 +2084,27 @@ "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "dev": true - }, "node_modules/@types/tern": { "version": "0.23.9", "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*" } }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.14.tgz", + "integrity": "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1931,6 +2114,7 @@ "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz", "integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1940,83 +2124,79 @@ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.15.0.tgz", - "integrity": "sha512-uiNHpyjZtFrLwLDpHnzaDlP3Tt6sGMqTCiqmxaN4n4RP0EfYZDODJyddiFDF44Hjwxr5xAcaYxVKm9QKQFJFLA==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz", + "integrity": "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/type-utils": "7.15.0", - "@typescript-eslint/utils": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/type-utils": "8.24.1", + "@typescript-eslint/utils": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.15.0.tgz", - "integrity": "sha512-k9fYuQNnypLFcqORNClRykkGOMOj+pV6V91R4GO/l1FDGwpqmSwoOQrOHo3cGaH63e+D3ZiCAOsuS/D2c99j/A==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.1.tgz", + "integrity": "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/typescript-estree": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", "debug": "^4.3.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.15.0.tgz", - "integrity": "sha512-Q/1yrF/XbxOTvttNVPihxh1b9fxamjEoz2Os/Pe38OHwxC24CyCqXxGTOdpb4lt6HYtqw9HetA/Rf6gDGaMPlw==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.1.tgz", + "integrity": "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0" + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2024,39 +2204,37 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.15.0.tgz", - "integrity": "sha512-SkgriaeV6PDvpA6253PDVep0qCqgbO1IOBiycjnXsszNTVQe5flN5wR5jiczoEoDEnAqYFSFFc9al9BSGVltkg==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz", + "integrity": "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.15.0", - "@typescript-eslint/utils": "7.15.0", + "@typescript-eslint/typescript-estree": "8.24.1", + "@typescript-eslint/utils": "8.24.1", "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", - "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.1.tgz", + "integrity": "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2064,38 +2242,64 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.15.0.tgz", - "integrity": "sha512-gjyB/rHAopL/XxfmYThQbXbzRMGhZzGw6KpcMbfe8Q3nNQKStpxnUKeXb0KiN/fFDR42Z43szs6rY7eHk0zdGQ==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.1.tgz", + "integrity": "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/visitor-keys": "7.15.0", + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -2104,90 +2308,89 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.15.0.tgz", - "integrity": "sha512-hfDMDqaqOqsUVGiEPSMLR/AjTSCsmJwjpKkYQRo1FNbmW4tBwBspYDwO9eh7sKSTwMQgBw9/T4DHudPaqshRWA==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.1.tgz", + "integrity": "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.15.0", - "@typescript-eslint/types": "7.15.0", - "@typescript-eslint/typescript-estree": "7.15.0" + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/typescript-estree": "8.24.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.15.0.tgz", - "integrity": "sha512-Hqgy/ETgpt2L5xueA/zHHIl4fJI2O4XUE9l4+OIfbJIRSnTJb/QscncdqqZzofQegIJugRIF57OJea1khw2SDw==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.1.tgz", + "integrity": "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.15.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.24.1", + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/@vitejs/plugin-basic-ssl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", - "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.2.0.tgz", + "integrity": "sha512-mkQnxTkcldAzIsomk1UuLfAu9n+kpQ3JbHcpCp7d2Oo6ITtji8pHS3QToOWjhPFvNQSnhlkAjmGbhv2QvwO/7Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=14.6.0" + "node": ">=14.21.3" }, "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" } }, "node_modules/@vitejs/plugin-react": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", - "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", + "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", + "license": "MIT", "dependencies": { - "@babel/core": "^7.23.5", - "@babel/plugin-transform-react-jsx-self": "^7.23.3", - "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@babel/core": "^7.26.0", + "@babel/plugin-transform-react-jsx-self": "^7.25.9", + "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.0" + "react-refresh": "^0.14.2" }, "engines": { "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "node_modules/@vitejs/plugin-vue": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.0.tgz", - "integrity": "sha512-7n7KdUEtx/7Yl7I/WVAMZ1bEb0eVvXF3ummWTeLcs/9gvo9pJhuLdouSXGjdZ/MKD1acf1I272+X0RMua4/R3g==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz", + "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==", "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "vite": "^5.0.0", + "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, @@ -2315,10 +2518,11 @@ "peer": true }, "node_modules/@zip.js/zip.js": { - "version": "2.7.32", - "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.32.tgz", - "integrity": "sha512-9Ox1meDIvIKE23LLA7Fxd/ewJpKjj2KryH92doHRqx2406LmIzorsiMawL0qIK7dvwN9K+mfk47lauoIE0o1zQ==", + "version": "2.7.57", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.57.tgz", + "integrity": "sha512-BtonQ1/jDnGiMed6OkV6rZYW78gLmLswkHOzyMrMb+CAR7CZO8phOHO6c2qw6qb1g1betN7kwEHhhZk30dv+NA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "bun": ">=0.7.0", "deno": ">=1.0.0", @@ -2329,12 +2533,27 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2347,15 +2566,30 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2372,6 +2606,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2381,6 +2616,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2391,29 +2627,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansi-styles/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ansi-styles/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -2422,28 +2641,44 @@ "node": ">= 8" } }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dependencies": { - "dequal": "^2.0.3" + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" } }, "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" }, "engines": { "node": ">= 0.4" @@ -2457,6 +2692,7 @@ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2466,6 +2702,7 @@ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -2481,20 +2718,33 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.findlast": { + "node_modules/array.prototype.findlastindex": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -2511,15 +2761,16 @@ } }, "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2529,15 +2780,16 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2551,6 +2803,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -2563,19 +2816,19 @@ } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { "node": ">= 0.4" @@ -2588,13 +2841,32 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -2606,42 +2878,52 @@ } }, "node_modules/axobject-query": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", - "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", - "dependencies": { - "dequal": "^2.0.3" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" } }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/boolean": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, + "license": "MIT", "optional": true }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/braces": { @@ -2649,6 +2931,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -2657,9 +2940,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "funding": [ { "type": "opencollective", @@ -2674,11 +2957,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -2692,6 +2976,7 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -2701,6 +2986,7 @@ "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.6.0" } @@ -2710,6 +2996,7 @@ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", "dev": true, + "license": "MIT", "dependencies": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", @@ -2724,16 +3011,47 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -2747,14 +3065,15 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001579", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", - "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", + "version": "1.0.30001700", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz", + "integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==", "funding": [ { "type": "opencollective", @@ -2768,43 +3087,45 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -2817,6 +3138,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -2826,6 +3150,7 @@ "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.7.1.tgz", "integrity": "sha512-am9lR+HidiBtPtEYV7aFBpFJaQZhwJbYKr37cOHw0GGR+uiG0O79f20JNLjR0qEwPMuxOHvdBu4HHfimClBOCg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "mitt": "3.0.1", "urlpattern-polyfill": "10.0.0", @@ -2840,6 +3165,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -2851,6 +3177,7 @@ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", "dev": true, + "license": "MIT", "dependencies": { "mimic-response": "^1.0.0" }, @@ -2862,6 +3189,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "@types/estree": "^1.0.1", @@ -2877,32 +3205,54 @@ "license": "MIT" }, "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" }, "node_modules/colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.1.90" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -2911,13 +3261,15 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concurrently": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.5.1.tgz", "integrity": "sha512-FlSwNpGjWQfRwPLXvJ/OgysbBxPkWpiVjy1042b0U7on7S7qwwMIILRj7WTN1mTgqa582bG6NFuScOoh6Zgdag==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "date-fns": "^2.16.1", @@ -2935,68 +3287,18 @@ "node": ">=10.0.0" } }, - "node_modules/concurrently/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/concurrently/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/concurrently/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.1" }, @@ -3029,6 +3331,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "license": "MIT", "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -3040,17 +3343,19 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" }, "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3060,29 +3365,31 @@ } }, "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/inspect-js" } }, "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" }, @@ -3098,6 +3405,7 @@ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -3110,11 +3418,12 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3131,6 +3440,7 @@ "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -3140,6 +3450,7 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, + "license": "MIT", "dependencies": { "mimic-response": "^3.1.0" }, @@ -3155,6 +3466,7 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3166,12 +3478,14 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3181,6 +3495,7 @@ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -3190,6 +3505,7 @@ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -3207,6 +3523,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -3219,12 +3536,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.4.0" } }, "node_modules/detect-node": { @@ -3232,13 +3551,15 @@ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/devtools-protocol": { - "version": "0.0.1349977", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1349977.tgz", - "integrity": "sha512-5JcwlDKinshGSm+4AVLFCkokJUAKTgjmiorNmrGgYYKix1h8Ts9/fplQeK1xg/rACYw1JlEM2PwIEvny5QswKQ==", + "version": "0.0.1421213", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1421213.tgz", + "integrity": "sha512-E0JrRYeXiTZXJwFlJ0j8wz8TmM+VwCv128JaSyCEgTmyE54QE/GDhT4w6kS1m+nFKmulHWWrbrO2AHexZgcxFQ==", "dev": true, + "license": "BSD-3-Clause", "peer": true }, "node_modules/dezalgo": { @@ -3246,40 +3567,31 @@ "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", "dev": true, + "license": "ISC", "dependencies": { "asap": "^2.0.0", "wrappy": "1" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=12" }, @@ -3287,12 +3599,28 @@ "url": "https://dotenvx.com" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/electron": { - "version": "30.1.2", - "resolved": "https://registry.npmjs.org/electron/-/electron-30.1.2.tgz", - "integrity": "sha512-A5CFGwbA+HSXnzwjc8fP2GIezBcAb0uN/VbNGLOW8DHOYn07rvJ/1bAJECHUUzt5zbfohveG3hpMQiYpbktuDw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-30.5.1.tgz", + "integrity": "sha512-AhL7+mZ8Lg14iaNfoYTkXQ2qee8mmsQyllKdqxlpv/zrKgfxz6jNVtcRRbQtLxtF8yzcImWdfTQROpYiPumdbw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^20.9.0", @@ -3306,30 +3634,41 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.639", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.639.tgz", - "integrity": "sha512-CkKf3ZUVZchr+zDpAlNLEEy2NJJ9T64ULWaDgy3THXXlPVPkLu3VOs9Bac44nebVtdwl2geSj6AxTtGDOxoXhg==" + "version": "1.5.102", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.102.tgz", + "integrity": "sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q==", + "license": "ISC" }, "node_modules/electron/node_modules/@types/node": { - "version": "20.12.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.13.tgz", - "integrity": "sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==", + "version": "20.17.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.19.tgz", + "integrity": "sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==", "dev": true, + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, + "node_modules/electron/node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, + "license": "MIT", "dependencies": { "once": "^1.4.0" } @@ -3352,62 +3691,69 @@ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", "dev": true, + "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" }, "engines": { "node": ">= 0.4" @@ -3417,13 +3763,11 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -3433,40 +3777,45 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-iterator-helpers": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", - "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", + "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.2" + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -3475,37 +3824,44 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.4", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -3519,128 +3875,235 @@ "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", + "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "9.20.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.1.tgz", + "integrity": "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.11.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.20.0", + "@eslint/plugin-kit": "^0.2.5", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/eslint-plugin-internal-playwright": { - "resolved": "utils/eslint-plugin-internal-playwright", - "link": true + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } }, "node_modules/eslint-plugin-notice": { - "version": "0.9.10", - "resolved": "https://registry.npmjs.org/eslint-plugin-notice/-/eslint-plugin-notice-0.9.10.tgz", - "integrity": "sha512-rF79EuqdJKu9hhTmwUkNeSvLmmq03m/NXq/NHwUENHbdJ0wtoyOjxZBhW4QCug8v5xYE6cGe3AWkGqSIe9KUbQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-notice/-/eslint-plugin-notice-1.0.0.tgz", + "integrity": "sha512-M3VLQMZzZpvfTZ/vy9FmClIKq5rLBbQpM0KgfLZPJPrVXpmJYeobmmb+lfJzHWdNm8PWwvw8KlafQWo2N9xx1Q==", "dev": true, + "license": "MIT", "dependencies": { "find-root": "^1.1.0", - "lodash": "^4.17.15", + "lodash": "^4.17.21", "metric-lcs": "^0.1.2" }, "peerDependencies": { @@ -3648,28 +4111,29 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.35.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz", - "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==", + "version": "7.37.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", + "integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", + "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.19", + "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", - "object.values": "^1.2.0", + "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11", + "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "engines": { @@ -3680,122 +4144,72 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0.tgz", + "integrity": "sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" + "bin": { + "resolve": "bin/resolve" }, - "engines": { - "node": "*" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -3803,88 +4217,30 @@ "node": ">=10.13.0" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -3897,6 +4253,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -3909,6 +4266,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -3917,6 +4275,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" } @@ -3926,15 +4285,27 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", @@ -3954,19 +4325,21 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -3976,19 +4349,22 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", + "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -3998,20 +4374,22 @@ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, + "license": "MIT", "dependencies": { "pend": "~1.2.0" } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -4019,6 +4397,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4030,13 +4409,15 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -4049,39 +4430,85 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" }, "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/formidable": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/formidable": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", "dev": true, + "license": "MIT", "dependencies": { "dezalgo": "^1.0.4", "hexoid": "^1.0.0", @@ -4097,6 +4524,7 @@ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", @@ -4110,19 +4538,22 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -4136,20 +4567,24 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -4163,6 +4598,7 @@ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4171,6 +4607,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -4180,21 +4617,28 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", "dev": true, + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -4203,11 +4647,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, + "license": "MIT", "dependencies": { "pump": "^3.0.0" }, @@ -4219,14 +4678,15 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -4239,7 +4699,9 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4260,6 +4722,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -4267,33 +4730,12 @@ "node": ">= 6" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/global-agent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "dependencies": { "boolean": "^3.0.1", @@ -4307,28 +4749,13 @@ "node": ">=10.0" } }, - "node_modules/global-agent/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/global-agent/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, + "license": "ISC", "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -4336,28 +4763,24 @@ "node": ">=10" } }, - "node_modules/global-agent/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "optional": true - }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, + "license": "MIT", "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -4366,42 +4789,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4412,6 +4807,7 @@ "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", "dev": true, + "license": "MIT", "dependencies": { "@sindresorhus/is": "^4.0.0", "@szmarczak/http-timer": "^4.0.5", @@ -4436,29 +4832,37 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/has-property-descriptors": { @@ -4466,6 +4870,7 @@ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -4474,10 +4879,14 @@ } }, "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -4486,10 +4895,11 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4502,6 +4912,7 @@ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -4517,6 +4928,7 @@ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -4529,6 +4941,7 @@ "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4537,7 +4950,8 @@ "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/html-reporter": { "resolved": "packages/html-reporter", @@ -4547,13 +4961,15 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/http2-wrapper": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", "dev": true, + "license": "MIT", "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.0.0" @@ -4562,11 +4978,22 @@ "node": ">=10.19.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -4575,13 +5002,15 @@ "version": "4.3.7", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -4598,6 +5027,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -4606,7 +5036,9 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -4616,30 +5048,34 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -4649,12 +5085,17 @@ } }, "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -4664,12 +5105,16 @@ } }, "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4680,6 +5125,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -4688,13 +5134,14 @@ } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4708,6 +5155,7 @@ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4716,23 +5164,30 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, + "license": "MIT", "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" }, "engines": { @@ -4743,12 +5198,14 @@ } }, "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4762,17 +5219,22 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4783,17 +5245,22 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -4807,6 +5274,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -4819,18 +5287,7 @@ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4843,17 +5300,20 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4862,31 +5322,26 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-inside": { + "node_modules/is-reference": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-reference": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", - "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "license": "MIT", "dependencies": { - "@types/estree": "*" + "@types/estree": "^1.0.6" } }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -4900,6 +5355,7 @@ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4908,12 +5364,13 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -4923,12 +5380,14 @@ } }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4938,12 +5397,15 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -4953,12 +5415,13 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, + "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -4972,6 +5435,7 @@ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4980,25 +5444,30 @@ } }, "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -5011,37 +5480,46 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", "dev": true, + "license": "MIT", "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -5050,51 +5528,58 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true, + "license": "ISC", "optional": true }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -5107,6 +5592,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, + "license": "MIT", "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -5116,6 +5602,7 @@ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", @@ -5131,6 +5618,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -5139,6 +5627,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", "engines": { "node": ">=6" } @@ -5148,6 +5637,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -5161,6 +5651,7 @@ "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "chalk": "^2.4.1", "debug": "^3.1.0", @@ -5177,34 +5668,116 @@ "license-checker": "bin/license-checker" } }, + "node_modules/license-checker/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/license-checker/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/license-checker/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/license-checker/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, "node_modules/license-checker/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, + "node_modules/license-checker/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/license-checker/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/license-checker/node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } }, + "node_modules/license-checker/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", - "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -5219,19 +5792,21 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -5244,6 +5819,7 @@ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5252,14 +5828,15 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, "node_modules/magic-string": { - "version": "0.30.15", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.15.tgz", - "integrity": "sha512-zXeaYRgZ6ldS1RJJUrMrYgNJ4fdwnyI6tVqoiIhyCyv5IVTK9BU8Ic2l253GGETQHxI4HNUwhJ3fjDhKqEoaAw==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" @@ -5270,6 +5847,7 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -5283,15 +5861,29 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } }, + "node_modules/markdown-to-jsx": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.7.4.tgz", + "integrity": "sha512-1bSfXyBKi+EYS3YY+e0Csuxf8oZ3decdfhOav/Z7Wrk89tjudyL5FOmwZQUoy0/qVXGUl+6Q3s2SWtpDEWITfQ==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "escape-string-regexp": "^4.0.0" @@ -5300,29 +5892,28 @@ "node": ">=10" } }, - "node_modules/matcher/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, - "optional": true, + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, "node_modules/mdn-data": { "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "license": "CC0-1.0" }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -5331,13 +5922,15 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/metric-lcs/-/metric-lcs-0.1.2.tgz", "integrity": "sha512-+TZ5dUDPKPJaU/rscTzxyN8ZkX7eAVLAiQU/e+YINleXPv03SCmJShaMT1If1liTH8OcmWXZs0CmzCBRBLcMpA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -5346,11 +5939,25 @@ "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -5358,28 +5965,50 @@ "node": ">=10.0.0" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/minimist": { @@ -5387,6 +6016,7 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5395,13 +6025,15 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, @@ -5410,9 +6042,10 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.8", @@ -5436,31 +6069,76 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + "dev": true, + "license": "MIT" }, - "node_modules/node-stream-zip": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", - "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==", + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", "engines": { - "node": ">=0.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/antelle" + "node": ">=10.5.0" } }, - "node_modules/nopt": { - "version": "4.0.3", + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "license": "MIT" + }, + "node_modules/node-stream-zip": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", + "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/antelle" + } + }, + "node_modules/nopt": { + "version": "4.0.3", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", "dev": true, + "license": "ISC", "dependencies": { "abbrev": "1", "osenv": "^0.1.4" @@ -5474,6 +6152,7 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -5481,28 +6160,12 @@ "validate-npm-package-license": "^3.0.1" } }, - "node_modules/normalize-package-data/node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/normalize-package-data/node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -5512,6 +6175,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5521,6 +6185,7 @@ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -5532,22 +6197,28 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5557,19 +6228,23 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" }, "engines": { @@ -5584,6 +6259,7 @@ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -5598,6 +6274,7 @@ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -5611,14 +6288,31 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" }, "engines": { @@ -5633,22 +6327,55 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } }, + "node_modules/openai": { + "version": "4.85.1", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.85.1.tgz", + "integrity": "sha512-jkX2fntHljUvSH3MkWh4jShl10oNkb+SsCj4auKlbu2oF4KWAnmHLNR5EpnUHK1ZNW05Rp0fjbJzYwQzMsH8ZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -5659,6 +6386,7 @@ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5668,6 +6396,7 @@ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5676,17 +6405,38 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "deprecated": "This package is no longer supported.", "dev": true, + "license": "ISC", "dependencies": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5696,6 +6446,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -5711,6 +6462,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -5726,6 +6478,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -5738,6 +6491,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5747,6 +6501,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5756,6 +6511,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5764,27 +6520,21 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, - "engines": { - "node": ">=8" - } + "license": "MIT" }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/periscopic": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^3.0.0", @@ -5798,12 +6548,13 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -5814,6 +6565,7 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5839,18 +6591,19 @@ "link": true }, "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.2.tgz", + "integrity": "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==", "funding": [ { "type": "opencollective", @@ -5867,7 +6620,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -5880,6 +6633,7 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -5889,6 +6643,7 @@ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -5898,6 +6653,7 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dev": true, + "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -5905,10 +6661,11 @@ } }, "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", "dev": true, + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -5919,17 +6676,19 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -5956,13 +6715,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -5971,10 +6732,10 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" }, @@ -5983,28 +6744,31 @@ } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dev": true, + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.3.1" } }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/react-refresh": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", - "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6013,7 +6777,9 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", + "deprecated": "This package is no longer supported.", "dev": true, + "license": "ISC", "dependencies": { "debuglog": "^1.0.1", "read-package-json": "^2.0.0", @@ -6031,6 +6797,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -6039,7 +6806,9 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.1", "json-parse-even-better-errors": "^2.3.0", @@ -6053,6 +6822,7 @@ "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", "deprecated": "This functionality has been moved to @npmcli/fs", "dev": true, + "license": "ISC", "dependencies": { "debuglog": "^1.0.1", "dezalgo": "^1.0.0", @@ -6065,6 +6835,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -6072,23 +6843,38 @@ "node": ">=8.10.0" } }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/recorder": { "resolved": "packages/recorder", "link": true }, "node_modules/reflect.getprototypeof": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", - "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.23.1", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -6101,18 +6887,22 @@ "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -6126,23 +6916,28 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6151,13 +6946,15 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -6167,6 +6964,7 @@ "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", "dev": true, + "license": "MIT", "dependencies": { "lowercase-keys": "^2.0.0" }, @@ -6179,31 +6977,18 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "dependencies": { "boolean": "^3.0.1", @@ -6218,11 +7003,12 @@ } }, "node_modules/rollup": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", - "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", + "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", + "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.6" }, "bin": { "rollup": "dist/bin/rollup" @@ -6232,22 +7018,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.22.4", - "@rollup/rollup-android-arm64": "4.22.4", - "@rollup/rollup-darwin-arm64": "4.22.4", - "@rollup/rollup-darwin-x64": "4.22.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.22.4", - "@rollup/rollup-linux-arm-musleabihf": "4.22.4", - "@rollup/rollup-linux-arm64-gnu": "4.22.4", - "@rollup/rollup-linux-arm64-musl": "4.22.4", - "@rollup/rollup-linux-powerpc64le-gnu": "4.22.4", - "@rollup/rollup-linux-riscv64-gnu": "4.22.4", - "@rollup/rollup-linux-s390x-gnu": "4.22.4", - "@rollup/rollup-linux-x64-gnu": "4.22.4", - "@rollup/rollup-linux-x64-musl": "4.22.4", - "@rollup/rollup-win32-arm64-msvc": "4.22.4", - "@rollup/rollup-win32-ia32-msvc": "4.22.4", - "@rollup/rollup-win32-x64-msvc": "4.22.4", + "@rollup/rollup-android-arm-eabi": "4.34.8", + "@rollup/rollup-android-arm64": "4.34.8", + "@rollup/rollup-darwin-arm64": "4.34.8", + "@rollup/rollup-darwin-x64": "4.34.8", + "@rollup/rollup-freebsd-arm64": "4.34.8", + "@rollup/rollup-freebsd-x64": "4.34.8", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", + "@rollup/rollup-linux-arm-musleabihf": "4.34.8", + "@rollup/rollup-linux-arm64-gnu": "4.34.8", + "@rollup/rollup-linux-arm64-musl": "4.34.8", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", + "@rollup/rollup-linux-riscv64-gnu": "4.34.8", + "@rollup/rollup-linux-s390x-gnu": "4.34.8", + "@rollup/rollup-linux-x64-gnu": "4.34.8", + "@rollup/rollup-linux-x64-musl": "4.34.8", + "@rollup/rollup-win32-arm64-msvc": "4.34.8", + "@rollup/rollup-win32-ia32-msvc": "4.34.8", + "@rollup/rollup-win32-x64-msvc": "4.34.8", "fsevents": "~2.3.2" } }, @@ -6270,6 +7059,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -6279,6 +7069,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^1.9.0" }, @@ -6287,14 +7078,16 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, "engines": { @@ -6304,15 +7097,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", - "is-regex": "^1.1.4" + "is-regex": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -6322,16 +7133,18 @@ } }, "node_modules/sax": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", - "dev": true + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "dev": true, + "license": "ISC" }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dev": true, + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } @@ -6340,6 +7153,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -6349,6 +7163,7 @@ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/serialize-error": { @@ -6356,6 +7171,7 @@ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "type-fest": "^0.13.1" @@ -6372,6 +7188,7 @@ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -6389,6 +7206,7 @@ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -6399,16 +7217,32 @@ "node": ">= 0.4" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "dev": true, + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/shebang-regex": { @@ -6416,20 +7250,79 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -6443,6 +7336,7 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -6452,6 +7346,7 @@ "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", "dev": true, + "license": "ISC", "engines": { "node": "*" } @@ -6460,14 +7355,15 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/spawn-command": { - "version": "0.0.2-1", - "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", - "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", + "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", "dev": true }, "node_modules/spdx-compare": { @@ -6475,6 +7371,7 @@ "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", "dev": true, + "license": "MIT", "dependencies": { "array-find-index": "^1.0.2", "spdx-expression-parse": "^3.0.0", @@ -6486,44 +7383,50 @@ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", - "dev": true + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true, + "license": "CC0-1.0" }, "node_modules/spdx-ranges": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", - "dev": true + "dev": true, + "license": "(MIT AND CC-BY-3.0)" }, "node_modules/spdx-satisfies": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz", "integrity": "sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==", "dev": true, + "license": "MIT", "dependencies": { "spdx-compare": "^1.0.0", "spdx-expression-parse": "^3.0.0", @@ -6535,19 +7438,22 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "dev": true, + "license": "BSD-3-Clause", "optional": true }, "node_modules/ssim.js": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/ssim.js/-/ssim.js-3.5.0.tgz", "integrity": "sha512-Aj6Jl2z6oDmgYFFbQqK7fght19bXdOxY7Tj03nF+03M9gCBAjeIiO8/PlEGMfKDwYpw4q6iBqVq2YuREorGg/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -6558,23 +7464,25 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", - "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", + "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "regexp.prototype.flags": "^1.5.2", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -6588,21 +7496,26 @@ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", "dev": true, + "license": "MIT", "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" } }, "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -6612,15 +7525,20 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6630,6 +7548,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -6647,6 +7566,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -6654,11 +7574,22 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -6671,6 +7602,7 @@ "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "debug": "^4.1.0" }, @@ -6679,14 +7611,19 @@ } }, "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -6694,6 +7631,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6705,6 +7643,7 @@ "version": "4.2.19", "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.1", "@jridgewell/sourcemap-codec": "^1.4.15", @@ -6726,9 +7665,10 @@ } }, "node_modules/svelte-hmr": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", - "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", + "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", + "license": "ISC", "engines": { "node": "^12.20 || ^14.13.1 || >= 16" }, @@ -6736,17 +7676,12 @@ "svelte": "^3.19.0 || ^4.0.0" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -6754,6 +7689,13 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, "node_modules/trace-viewer": { "resolved": "packages/trace-viewer", "link": true @@ -6763,6 +7705,7 @@ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, + "license": "MIT", "bin": { "tree-kill": "cli.js" } @@ -6772,33 +7715,63 @@ "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6" } }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", "dev": true, + "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" } }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } @@ -6808,6 +7781,7 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -6820,6 +7794,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "dev": true, + "license": "(MIT OR CC0-1.0)", "optional": true, "engines": { "node": ">=10" @@ -6829,30 +7804,32 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -6862,17 +7839,19 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" }, "engines": { "node": ">= 0.4" @@ -6882,17 +7861,18 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-proto": "^1.0.3", "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" }, "engines": { "node": ">= 0.4" @@ -6902,9 +7882,9 @@ } }, "node_modules/typescript": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", - "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -6916,25 +7896,30 @@ } }, "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bound": "^1.0.3", "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/undici": { - "version": "5.28.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", - "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "version": "5.28.5", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz", + "integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==", "dev": true, + "license": "MIT", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -6946,21 +7931,23 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4.0.0" } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", + "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", "funding": [ { "type": "opencollective", @@ -6975,9 +7962,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -6991,6 +7979,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -6999,47 +7988,42 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/util-extend": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", - "dev": true - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } + "license": "MIT" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "node_modules/vite": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", - "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz", + "integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==", + "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.24.2", + "postcss": "^8.5.1", + "rollup": "^4.30.1" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -7048,19 +8032,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -7081,387 +8071,453 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", "cpu": [ "loong64" ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", "cpu": [ "mips64el" ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", "cpu": [ "riscv64" ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", "cpu": [ "s390x" ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/vite/node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/vitefu": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", - "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" } }, "node_modules/vue": { @@ -7490,11 +8546,40 @@ "resolved": "packages/web", "link": true }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -7506,39 +8591,45 @@ } }, "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "dev": true, + "license": "MIT", "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-builtin-type": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", - "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "dev": true, + "license": "MIT", "dependencies": { + "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", + "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", + "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", - "which-typed-array": "^1.1.15" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -7552,6 +8643,7 @@ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, + "license": "MIT", "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", @@ -7566,15 +8658,17 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", + "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "for-each": "^0.3.3", - "gopd": "^1.0.1", + "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" }, "engines": { @@ -7584,11 +8678,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -7605,13 +8710,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -7633,6 +8740,7 @@ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, + "license": "MIT", "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" @@ -7646,6 +8754,7 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0" } @@ -7653,12 +8762,16 @@ "node_modules/xterm": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz", - "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==" + "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==", + "deprecated": "This package is now deprecated. Move to @xterm/xterm instead.", + "license": "MIT" }, "node_modules/xterm-addon-fit": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.7.0.tgz", "integrity": "sha512-tQgHGoHqRTgeROPnvmtEJywLKoC/V9eNs4bLLz7iyJr1aW/QFzRwfd3MGiJ6odJd9xEfxcW36/xRU47JkD5NKQ==", + "deprecated": "This package is now deprecated. Move to @xterm/addon-fit instead.", + "license": "MIT", "peerDependencies": { "xterm": "^5.0.0" } @@ -7668,6 +8781,7 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -7675,7 +8789,8 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" }, "node_modules/yaml": { "version": "2.6.0", @@ -7694,6 +8809,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -7712,6 +8828,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -7721,6 +8838,7 @@ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, + "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" @@ -7731,6 +8849,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -7743,6 +8862,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -7751,10 +8871,10 @@ "version": "0.0.0" }, "packages/playwright": { - "version": "1.50.0-next", + "version": "1.51.1", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" }, "bin": { "playwright": "cli.js" @@ -7768,11 +8888,11 @@ }, "packages/playwright-browser-chromium": { "name": "@playwright/browser-chromium", - "version": "1.50.0-next", + "version": "1.51.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" }, "engines": { "node": ">=18" @@ -7780,11 +8900,11 @@ }, "packages/playwright-browser-firefox": { "name": "@playwright/browser-firefox", - "version": "1.50.0-next", + "version": "1.51.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" }, "engines": { "node": ">=18" @@ -7792,22 +8912,22 @@ }, "packages/playwright-browser-webkit": { "name": "@playwright/browser-webkit", - "version": "1.50.0-next", + "version": "1.51.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" }, "engines": { "node": ">=18" } }, "packages/playwright-chromium": { - "version": "1.50.0-next", + "version": "1.51.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" }, "bin": { "playwright": "cli.js" @@ -7816,8 +8936,19 @@ "node": ">=18" } }, + "packages/playwright-client": { + "name": "@playwright/client", + "version": "0.0.0", + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.51.1" + }, + "engines": { + "node": ">=18" + } + }, "packages/playwright-core": { - "version": "1.50.0-next", + "version": "1.51.1", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -7828,12 +8959,12 @@ }, "packages/playwright-ct-core": { "name": "@playwright/experimental-ct-core", - "version": "1.50.0-next", + "version": "1.51.1", "license": "Apache-2.0", "dependencies": { - "playwright": "1.50.0-next", - "playwright-core": "1.50.0-next", - "vite": "^5.2.8" + "playwright": "1.51.1", + "playwright-core": "1.51.1", + "vite": "^5.4.14 || ^6.0.0" }, "engines": { "node": ">=18" @@ -7841,10 +8972,10 @@ }, "packages/playwright-ct-react": { "name": "@playwright/experimental-ct-react", - "version": "1.50.0-next", + "version": "1.51.1", "license": "Apache-2.0", "dependencies": { - "@playwright/experimental-ct-core": "1.50.0-next", + "@playwright/experimental-ct-core": "1.51.1", "@vitejs/plugin-react": "^4.2.1" }, "bin": { @@ -7856,10 +8987,10 @@ }, "packages/playwright-ct-react17": { "name": "@playwright/experimental-ct-react17", - "version": "1.50.0-next", + "version": "1.51.1", "license": "Apache-2.0", "dependencies": { - "@playwright/experimental-ct-core": "1.50.0-next", + "@playwright/experimental-ct-core": "1.51.1", "@vitejs/plugin-react": "^4.2.1" }, "bin": { @@ -7871,10 +9002,10 @@ }, "packages/playwright-ct-svelte": { "name": "@playwright/experimental-ct-svelte", - "version": "1.50.0-next", + "version": "1.51.1", "license": "Apache-2.0", "dependencies": { - "@playwright/experimental-ct-core": "1.50.0-next", + "@playwright/experimental-ct-core": "1.51.1", "@sveltejs/vite-plugin-svelte": "^3.0.1" }, "bin": { @@ -7887,27 +9018,570 @@ "node": ">=18" } }, - "packages/playwright-ct-vue": { - "name": "@playwright/experimental-ct-vue", - "version": "1.50.0-next", - "license": "Apache-2.0", - "dependencies": { - "@playwright/experimental-ct-core": "1.50.0-next", - "@vitejs/plugin-vue": "^5.2.0" - }, - "bin": { - "playwright": "cli.js" - }, + "packages/playwright-ct-svelte/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "peer": true, "engines": { - "node": ">=18" + "node": ">=12" } }, - "packages/playwright-firefox": { - "version": "1.50.0-next", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "playwright-core": "1.50.0-next" + "packages/playwright-ct-svelte/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "packages/playwright-ct-svelte/node_modules/@sveltejs/vite-plugin-svelte": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz", + "integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==", + "license": "MIT", + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", + "debug": "^4.3.4", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.10", + "svelte-hmr": "^0.16.0", + "vitefu": "^0.2.5" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "packages/playwright-ct-svelte/node_modules/@sveltejs/vite-plugin-svelte/node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", + "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "packages/playwright-ct-svelte/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "packages/playwright-ct-svelte/node_modules/vite": { + "version": "5.4.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", + "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "packages/playwright-ct-svelte/node_modules/vitefu": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "license": "MIT", + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "packages/playwright-ct-vue": { + "name": "@playwright/experimental-ct-vue", + "version": "1.51.1", + "license": "Apache-2.0", + "dependencies": { + "@playwright/experimental-ct-core": "1.51.1", + "@vitejs/plugin-vue": "^5.2.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "packages/playwright-firefox": { + "version": "1.51.1", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.51.1" }, "bin": { "playwright": "cli.js" @@ -7918,10 +9592,10 @@ }, "packages/playwright-test": { "name": "@playwright/test", - "version": "1.50.0-next", + "version": "1.51.1", "license": "Apache-2.0", "dependencies": { - "playwright": "1.50.0-next" + "playwright": "1.51.1" }, "bin": { "playwright": "cli.js" @@ -7930,12 +9604,27 @@ "node": ">=18" } }, + "packages/playwright-tools": { + "name": "@playwright/experimental-tools", + "version": "0.0.0", + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.51.1" + }, + "devDependencies": { + "@anthropic-ai/sdk": "^0.33.1", + "openai": "^4.79.1" + }, + "engines": { + "node": ">=18" + } + }, "packages/playwright-webkit": { - "version": "1.50.0-next", + "version": "1.51.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" }, "bin": { "playwright": "cli.js" @@ -7949,6 +9638,7 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -7966,6 +9656,7 @@ "packages/trace-viewer": { "version": "0.0.0", "dependencies": { + "markdown-to-jsx": "^7.7.3", "yaml": "^2.6.0" } }, @@ -7976,10 +9667,6 @@ "xterm": "^5.1.0", "xterm-addon-fit": "^0.7.0" } - }, - "utils/eslint-plugin-internal-playwright": { - "version": "0.0.1", - "dev": true } } } diff --git a/package.json b/package.json index 5eafd4d8050dc..a1e70154d67dc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "playwright-internal", "private": true, - "version": "1.50.0-next", + "version": "1.51.1", "description": "A high-level API to automate web browsers", "repository": { "type": "git", @@ -30,14 +30,14 @@ "ttest": "node ./tests/playwright-test/stable-test-runner/node_modules/@playwright/test/cli test --config=tests/playwright-test/playwright.config.ts", "ct": "playwright test tests/components/test-all.spec.js --reporter=list", "test": "playwright test --config=tests/library/playwright.config.ts", - "eslint": "eslint --cache --report-unused-disable-directives --ext ts,tsx,js,jsx,mjs .", + "eslint": "eslint --cache && eslint -c eslint-react.config.mjs", "tsc": "tsc -p . && tsc -p packages/html-reporter/", "build-installer": "babel -s --extensions \".ts\" --out-dir packages/playwright-core/lib/utils/ packages/playwright-core/src/utils", "doc": "node utils/doclint/cli.js", "lint": "npm run eslint && npm run tsc && npm run doc && npm run check-deps && node utils/generate_channels.js && node utils/generate_types/ && npm run lint-tests && npm run test-types && npm run lint-packages", "lint-packages": "node utils/workspace.js --ensure-consistent", "lint-tests": "node utils/lint_tests.js", - "flint": "concurrently \"npm run eslint\" \"npm run tsc\" \"npm run doc\" \"npm run check-deps\" \"node utils/generate_channels.js\" \"node utils/generate_types/\" \"npm run lint-tests\" \"npm run test-types\" \"npm run lint-packages\"", + "flint": "concurrently \"npm run eslint\" \"npm run tsc\" \"npm run doc\" \"npm run check-deps\" \"node utils/generate_channels.js\" \"node utils/generate_types/\" \"npm run lint-tests\" \"npm run test-types\" \"npm run lint-packages\" \"node utils/doclint/linting-code-snippets/cli.js --js-only\"", "clean": "node utils/build/clean.js", "build": "node utils/build/build.js", "watch": "node utils/build/build.js --watch --lint", @@ -62,6 +62,10 @@ "@babel/plugin-transform-optional-chaining": "^7.23.4", "@babel/plugin-transform-typescript": "^7.23.6", "@babel/preset-react": "^7.23.3", + "@eslint/compat": "^1.2.6", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "^9.19.0", + "@stylistic/eslint-plugin": "^3.0.1", "@types/babel__core": "^7.20.2", "@types/codemirror": "^5.60.7", "@types/formidable": "^2.0.4", @@ -71,9 +75,9 @@ "@types/react-dom": "^18.0.5", "@types/ws": "^8.5.3", "@types/xml2js": "^0.4.9", - "@typescript-eslint/eslint-plugin": "^7.15.0", - "@typescript-eslint/parser": "^7.15.0", - "@typescript-eslint/utils": "^7.15.0", + "@typescript-eslint/eslint-plugin": "^8.23.0", + "@typescript-eslint/parser": "^8.23.0", + "@typescript-eslint/utils": "^8.23.0", "@vitejs/plugin-basic-ssl": "^1.1.0", "@vitejs/plugin-react": "^4.2.1", "@zip.js/zip.js": "^2.7.29", @@ -85,24 +89,25 @@ "cross-env": "^7.0.3", "dotenv": "^16.4.5", "electron": "^30.1.2", - "esbuild": "^0.18.11", - "eslint": "^8.55.0", - "eslint-plugin-internal-playwright": "file:utils/eslint-plugin-internal-playwright", - "eslint-plugin-notice": "^0.9.10", - "eslint-plugin-react": "^7.35.0", - "eslint-plugin-react-hooks": "^4.6.2", + "esbuild": "^0.25.0", + "eslint": "^9.19.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-notice": "^1.0.0", + "eslint-plugin-react": "^7.37.4", + "eslint-plugin-react-hooks": "^5.1.0", "formidable": "^2.1.1", "immutable": "^4.3.7", "license-checker": "^25.0.1", + "markdown-to-jsx": "^7.7.3", "mime": "^3.0.0", "node-stream-zip": "^1.15.0", "react": "^18.1.0", "react-dom": "^18.1.0", "ssim.js": "^3.5.0", - "typescript": "^5.7.2", - "vite": "^5.4.6", + "typescript": "^5.7.3", + "vite": "^6.1.0", "ws": "^8.17.1", "xml2js": "^0.5.0", - "yaml": "^2.6.0" + "yaml": "2.6.0" } } diff --git a/packages/.eslintrc.js b/packages/.eslintrc.js deleted file mode 100644 index 54c58ce323b5d..0000000000000 --- a/packages/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - "extends": "../.eslintrc.js", - /** - * ESLint rules - * - * All available rules: http://eslint.org/docs/rules/ - * - * Rules take the following form: - * "rule-name", [severity, { opts }] - * Severity: 2 == error, 1 == warning, 0 == off. - */ - "rules": { - "no-console": 2, - "no-debugger": 2, - "no-restricted-properties": [2, { - "object": "process", - "property": "exit", - "message": "Please use gracefullyProcessExitDoNotHang function to exit the process.", - }], - } -}; diff --git a/packages/html-reporter/index.html b/packages/html-reporter/index.html index 054507220c9e8..54ab833d2b4c8 100644 --- a/packages/html-reporter/index.html +++ b/packages/html-reporter/index.html @@ -15,7 +15,7 @@ --> - + diff --git a/packages/html-reporter/playwright.config.ts b/packages/html-reporter/playwright.config.ts index 1e6cb8b8a3c74..1f849f807eae1 100644 --- a/packages/html-reporter/playwright.config.ts +++ b/packages/html-reporter/playwright.config.ts @@ -23,7 +23,11 @@ export default defineConfig({ forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, snapshotPathTemplate: '{testDir}/__screenshots__/{projectName}/{testFilePath}/{arg}{ext}', - reporter: process.env.CI ? 'blob' : 'html', + reporter: process.env.CI ? [ + ['blob', { fileName: `${process.env.PWTEST_BOT_NAME}.zip` }], + ] : [ + ['html'] + ], use: { ctPort: 3101, ctViteConfig: { diff --git a/packages/html-reporter/src/common.css b/packages/html-reporter/src/common.css index 12241fd86160b..63ad3cd70fa04 100644 --- a/packages/html-reporter/src/common.css +++ b/packages/html-reporter/src/common.css @@ -267,6 +267,26 @@ article, aside, details, figcaption, figure, footer, header, main, menu, nav, se flex: none; } +.button { + flex: none; + height: 24px; + border: 1px solid var(--color-btn-border); + outline: none; + color: var(--color-btn-text); + background: var(--color-btn-bg); + padding: 4px; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 4px; +} + +.button:not(:disabled):hover { + border-color: var(--color-btn-hover-border); + background-color: var(--color-btn-hover-bg); +} + @media only screen and (max-width: 600px) { .subnav-item, .form-control { border-radius: 0 !important; diff --git a/packages/html-reporter/src/copyToClipboard.tsx b/packages/html-reporter/src/copyToClipboard.tsx index 17b1dfbf95443..8171cdd6c3205 100644 --- a/packages/html-reporter/src/copyToClipboard.tsx +++ b/packages/html-reporter/src/copyToClipboard.tsx @@ -39,7 +39,7 @@ export const CopyToClipboard: React.FunctionComponent = ({ }); }, [value]); const iconElement = icon === 'check' ? icons.check() : icon === 'cross' ? icons.cross() : icons.copy(); - return ; + return ; }; type CopyToClipboardContainerProps = CopyToClipboardProps & { diff --git a/packages/html-reporter/src/icons.tsx b/packages/html-reporter/src/icons.tsx index 9609a2e23f1ad..ffe6a08fcf015 100644 --- a/packages/html-reporter/src/icons.tsx +++ b/packages/html-reporter/src/icons.tsx @@ -69,22 +69,6 @@ export const blank = () => { return ; }; -export const externalLink = () => { - return ; -}; - -export const calendar = () => { - return ; -}; - -export const person = () => { - return ; -}; - -export const commit = () => { - return ; -}; - export const image = () => { return
{linkifyText(attachment.body!)}
]; - } : undefined} depth={0} style={{ lineHeight: '32px' }} selected={isAnchored}>; + } : undefined} depth={0} style={{ lineHeight: '32px' }} flash={flash}>; }; export const SearchParamsContext = React.createContext(new URLSearchParams(window.location.hash.slice(1))); @@ -118,12 +119,12 @@ const kMissingContentType = 'x-playwright/missing'; export type AnchorID = string | string[] | ((id: string) => boolean) | undefined; -export function useAnchor(id: AnchorID, onReveal: () => void) { +export function useAnchor(id: AnchorID, onReveal: React.EffectCallback) { const searchParams = React.useContext(SearchParamsContext); const isAnchored = useIsAnchored(id); React.useEffect(() => { if (isAnchored) - onReveal(); + return onReveal(); }, [isAnchored, onReveal, searchParams]); } diff --git a/packages/html-reporter/src/metadataView.css b/packages/html-reporter/src/metadataView.css new file mode 100644 index 0000000000000..c383d6776a0e9 --- /dev/null +++ b/packages/html-reporter/src/metadataView.css @@ -0,0 +1,67 @@ +/* + Copyright (c) Microsoft Corporation. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +.metadata-toggle { + cursor: pointer; + user-select: none; + margin-left: 5px; + color: var(--color-fg-default); +} + +.metadata-view { + border: 1px solid var(--color-border-default); + border-radius: 6px; + margin-top: 8px; +} + +.metadata-view .metadata-section { + margin: 8px 10px 8px 32px; +} + +.metadata-view span:not(.copy-button-container), +.metadata-view a { + display: inline-block; + line-height: 24px; +} + +.metadata-properties { + display: flex; + flex-direction: column; + align-items: normal; + gap: 8px; +} + +.metadata-properties > div { + height: 24px; +} + +.metadata-separator { + height: 1px; + border-bottom: 1px solid var(--color-border-default); +} + +.metadata-view a { + color: var(--color-fg-default); +} + +.copyable-property { + white-space: pre; +} + +.copyable-property > span { + display: flex; + align-items: center; +} diff --git a/packages/html-reporter/src/metadataView.tsx b/packages/html-reporter/src/metadataView.tsx index 0f4fe6e73c652..545eb14513a8a 100644 --- a/packages/html-reporter/src/metadataView.tsx +++ b/packages/html-reporter/src/metadataView.tsx @@ -17,21 +17,13 @@ import * as React from 'react'; import './colors.css'; import './common.css'; -import * as icons from './icons'; -import { AutoChip } from './chip'; -import './reportView.css'; import './theme.css'; - -export type Metainfo = { - 'revision.id'?: string; - 'revision.author'?: string; - 'revision.email'?: string; - 'revision.subject'?: string; - 'revision.timestamp'?: number | Date; - 'revision.link'?: string; - 'ci.link'?: string; - 'timestamp'?: number -}; +import './metadataView.css'; +import type { Metadata } from '@playwright/test'; +import type { CIInfo, GitCommitInfo, MetadataWithCommitInfo } from '@testIsomorphic/types'; +import { CopyToClipboardContainer } from './copyToClipboard'; +import { linkifyText } from '@web/renderUtils'; +import { SearchParamsContext } from './links'; class ErrorBoundary extends React.Component, { error: Error | null, errorInfo: React.ErrorInfo | null }> { override state: { error: Error | null, errorInfo: React.ErrorInfo | null } = { @@ -46,12 +38,12 @@ class ErrorBoundary extends React.Component, { error override render() { if (this.state.error || this.state.errorInfo) { return ( - -

An error was encountered when trying to render Commit Metainfo. Please file a GitHub issue to report this error.

+
+

An error was encountered when trying to render metadata.

{this.state.error?.message}
{this.state.error?.stack}
{this.state.errorInfo?.componentStack}

- +
); } @@ -59,79 +51,71 @@ class ErrorBoundary extends React.Component, { error } } -export const MetadataView: React.FC = metadata => ; +export const MetadataView: React.FC<{ metadata: Metadata }> = params => { + return ; +}; -const InnerMetadataView: React.FC = metadata => { - if (!Object.keys(metadata).find(k => k.startsWith('revision.') || k.startsWith('ci.'))) - return null; +const InnerMetadataView: React.FC<{ metadata: Metadata }> = params => { + const searchParams = React.useContext(SearchParamsContext); + const commitInfo = params.metadata as MetadataWithCommitInfo; + const otherEntries = searchParams.has('show-metadata-other') ? Object.entries(params.metadata).filter(([key]) => !ignoreKeys.has(key)) : []; + const hasMetadata = commitInfo.ci || commitInfo.gitCommit || otherEntries.length > 0; + if (!hasMetadata) + return; + return
+ {commitInfo.ci && !commitInfo.gitCommit && } + {commitInfo.gitCommit && } + {otherEntries.length > 0 && (commitInfo.gitCommit || commitInfo.ci) &&
} +
+ {otherEntries.map(([propertyName, value]) => { + const valueString = typeof value !== 'object' || value === null || value === undefined ? String(value) : JSON.stringify(value); + const trimmedValue = valueString.length > 1000 ? valueString.slice(0, 1000) + '\u2026' : valueString; + return ( +
+ + {propertyName} + : {linkifyText(trimmedValue)} + +
+ ); + })} +
+
; +}; - return ( - - {metadata['revision.id'] && - {metadata['revision.id'].slice(0, 7)} - } - {metadata['revision.subject'] || 'Commit Metainfo'} - } initialExpanded={false} dataTestId='metadata-chip'> - {metadata['revision.subject'] && - {metadata['revision.subject']}} - /> - } - {metadata['revision.id'] && - {metadata['revision.id']}} - href={metadata['revision.link']} - icon='commit' - /> - } - {(metadata['revision.author'] || metadata['revision.email']) && - - } - {metadata['revision.timestamp'] && - - {Intl.DateTimeFormat(undefined, { dateStyle: 'full' }).format(metadata['revision.timestamp'])} - {' '} - {Intl.DateTimeFormat(undefined, { timeStyle: 'long' }).format(metadata['revision.timestamp'])} - - } - icon='calendar' - /> - } - {metadata['ci.link'] && - - } - {metadata['timestamp'] && - - Report generated on {Intl.DateTimeFormat(undefined, { dateStyle: 'full', timeStyle: 'long' }).format(metadata['timestamp'])} - }> - } - - ); +const CiInfoView: React.FC<{ info: CIInfo }> = ({ info }) => { + const title = info.prTitle || `Commit ${info.commitHash}`; + const link = info.prHref || info.commitHref; + return
+
+ {title} +
+
; }; -const MetadataViewItem: React.FC<{ content: JSX.Element | string; icon?: keyof typeof icons, href?: string, testId?: string }> = ({ content, icon, href, testId }) => { - return ( -
-
- {icons[icon || 'blank']()} -
-
- {href ? {content} : content} -
+const GitCommitInfoView: React.FC<{ ci?: CIInfo, commit: GitCommitInfo }> = ({ ci, commit }) => { + const title = ci?.prTitle || commit.subject; + const link = ci?.prHref || ci?.commitHref; + const email = ` <${commit.author.email}>`; + const author = `${commit.author.name}${email}`; + const shortTimestamp = Intl.DateTimeFormat(undefined, { dateStyle: 'medium' }).format(commit.committer.time); + const longTimestamp = Intl.DateTimeFormat(undefined, { dateStyle: 'full', timeStyle: 'long' }).format(commit.committer.time); + + return
+
+ {link && {title}} + {!link && {title}} +
+
+ {author} + on {shortTimestamp}
- ); +
; +}; + +const ignoreKeys = new Set(['ci', 'gitCommit', 'gitDiff', 'actualWorkers']); + +export const isMetadataEmpty = (metadata: MetadataWithCommitInfo): boolean => { + const otherEntries = Object.entries(metadata).filter(([key]) => !ignoreKeys.has(key)); + return !metadata.ci && !metadata.gitCommit && !otherEntries.length; }; diff --git a/packages/html-reporter/src/reportView.tsx b/packages/html-reporter/src/reportView.tsx index cf0f5e5e56794..e48064201c26f 100644 --- a/packages/html-reporter/src/reportView.tsx +++ b/packages/html-reporter/src/reportView.tsx @@ -23,8 +23,6 @@ import { HeaderView } from './headerView'; import { Route, SearchParamsContext } from './links'; import type { LoadedReport } from './loadedReport'; import './reportView.css'; -import type { Metainfo } from './metadataView'; -import { MetadataView } from './metadataView'; import { TestCaseView } from './testCaseView'; import { TestFilesHeader, TestFilesView } from './testFilesView'; import './theme.css'; @@ -50,6 +48,7 @@ export const ReportView: React.FC<{ const searchParams = React.useContext(SearchParamsContext); const [expandedFiles, setExpandedFiles] = React.useState>(new Map()); const [filterText, setFilterText] = React.useState(searchParams.get('q') || ''); + const [metadataVisible, setMetadataVisible] = React.useState(false); const testIdToFileIdMap = React.useMemo(() => { const map = new Map(); @@ -76,9 +75,8 @@ export const ReportView: React.FC<{ return
{report?.json() && } - {report?.json().metadata && } - + setMetadataVisible(visible => !visible)}/> { - text: "My test test.spec.ts:42 10ms" `); }); + + +const testCaseWithTwoAttempts: TestCase = { + ...testCase, + results: [ + { + ...result, + errors: ['Error message'], + status: 'failed', + duration: 50, + }, + { + ...result, + duration: 150, + status: 'passed', + }, + ], +}; + +test('total duration is selected run duration', async ({ mount, page }) => { + const component = await mount(); + await expect(component).toMatchAriaSnapshot(` + - text: "My test test.spec.ts:42 200ms" + - text: "Run 50ms Retry #1 150ms" + `); + await page.locator('.tabbed-pane-tab-label', { hasText: 'Run50ms' }).click(); + await expect(component).toMatchAriaSnapshot(` + - text: "My test test.spec.ts:42 200ms" + `); + await page.locator('.tabbed-pane-tab-label', { hasText: 'Retry #1150ms' }).click(); + await expect(component).toMatchAriaSnapshot(` + - text: "My test test.spec.ts:42 200ms" + `); +}); diff --git a/packages/html-reporter/src/testCaseView.tsx b/packages/html-reporter/src/testCaseView.tsx index e4ffa9c15b9a4..ca5ff6d2e2b66 100644 --- a/packages/html-reporter/src/testCaseView.tsx +++ b/packages/html-reporter/src/testCaseView.tsx @@ -77,7 +77,10 @@ export const TestCaseView: React.FC<{ {test && ({ id: String(index), - title:
{statusIcon(result.status)} {retryLabel(index)}
, + title:
+ {statusIcon(result.status)} {retryLabel(index)} + {(test.results.length > 1) && {msToString(result.duration)}} +
, render: () => })) || []} selectedTab={String(selectedResultIndex)} setSelectedTab={id => setSelectedResultIndex(+id)} />}
; diff --git a/packages/html-reporter/src/testErrorView.css b/packages/html-reporter/src/testErrorView.css index e29ea2a18b08f..5b6b10389b665 100644 --- a/packages/html-reporter/src/testErrorView.css +++ b/packages/html-reporter/src/testErrorView.css @@ -16,18 +16,21 @@ @import '@web/third_party/vscode/colors.css'; -.test-error-view { +.test-error-container { white-space: pre; overflow: auto; flex: none; padding: 0; background-color: var(--color-canvas-subtle); border-radius: 6px; - padding: 16px; line-height: initial; margin-bottom: 6px; } +.test-error-view { + padding: 16px; +} + .test-error-text { font-family: monospace; } diff --git a/packages/html-reporter/src/testErrorView.tsx b/packages/html-reporter/src/testErrorView.tsx index ea402106a83aa..1ba843282928a 100644 --- a/packages/html-reporter/src/testErrorView.tsx +++ b/packages/html-reporter/src/testErrorView.tsx @@ -23,9 +23,43 @@ import { ImageDiffView } from '@web/shared/imageDiffView'; export const TestErrorView: React.FC<{ error: string; testId?: string; -}> = ({ error, testId }) => { - const html = React.useMemo(() => ansiErrorToHtml(error), [error]); - return
; + prompt?: string; +}> = ({ error, testId, prompt }) => { + return ( + + {prompt && ( +
+ +
+ )} +
+ ); +}; + +export const CodeSnippet = ({ code, children, testId }: React.PropsWithChildren<{ code: string; testId?: string; }>) => { + const html = React.useMemo(() => ansiErrorToHtml(code), [code]); + return ( +
+ {children} +
+
+ ); +}; + +const PromptButton: React.FC<{ prompt: string }> = ({ prompt }) => { + const [copied, setCopied] = React.useState(false); + return ; }; export const TestScreenshotErrorView: React.FC<{ diff --git a/packages/html-reporter/src/testFileView.css b/packages/html-reporter/src/testFileView.css index 72858846bb437..37bf428490476 100644 --- a/packages/html-reporter/src/testFileView.css +++ b/packages/html-reporter/src/testFileView.css @@ -69,4 +69,11 @@ .test-file-test-status-icon { flex: none; +} + +.test-file-header-info { + display: flex; + align-items: center; + gap: 8px; + color: var(--color-fg-subtle); } \ No newline at end of file diff --git a/packages/html-reporter/src/testFilesView.tsx b/packages/html-reporter/src/testFilesView.tsx index d21088f5757fb..4b2c48ae1d84e 100644 --- a/packages/html-reporter/src/testFilesView.tsx +++ b/packages/html-reporter/src/testFilesView.tsx @@ -21,6 +21,8 @@ import './testFileView.css'; import { msToString } from './utils'; import { AutoChip } from './chip'; import { TestErrorView } from './testErrorView'; +import * as icons from './icons'; +import { isMetadataEmpty, MetadataView } from './metadataView'; export const TestFilesView: React.FC<{ tests: TestFileSummary[], @@ -62,17 +64,25 @@ export const TestFilesView: React.FC<{ export const TestFilesHeader: React.FC<{ report: HTMLReport | undefined, filteredStats?: FilteredStats, -}> = ({ report, filteredStats }) => { + metadataVisible: boolean, + toggleMetadataVisible: () => void, +}> = ({ report, filteredStats, metadataVisible, toggleMetadataVisible }) => { if (!report) - return; + return null; return <> -
- {report.projectNames.length === 1 && !!report.projectNames[0] &&
Project: {report.projectNames[0]}
} - {filteredStats &&
Filtered: {filteredStats.total} {!!filteredStats.total && ('(' + msToString(filteredStats.duration) + ')')}
} +
+
+ {!isMetadataEmpty(report.metadata) &&
+ {metadataVisible ? icons.downArrow() : icons.rightArrow()}Metadata +
} + {report.projectNames.length === 1 && !!report.projectNames[0] &&
Project: {report.projectNames[0]}
} + {filteredStats &&
Filtered: {filteredStats.total} {!!filteredStats.total && ('(' + msToString(filteredStats.duration) + ')')}
} +
{report ? new Date(report.startTime).toLocaleString() : ''}
Total time: {msToString(report.duration ?? 0)}
+ {metadataVisible && } {!!report.errors.length && {report.errors.map((error, index) => )} } diff --git a/packages/html-reporter/src/testResultView.tsx b/packages/html-reporter/src/testResultView.tsx index 64497b3bcd10a..060a1aaba4f01 100644 --- a/packages/html-reporter/src/testResultView.tsx +++ b/packages/html-reporter/src/testResultView.tsx @@ -24,7 +24,7 @@ import { Anchor, AttachmentLink, generateTraceUrl, testResultHref } from './link import { statusIcon } from './statusIcon'; import type { ImageDiff } from '@web/shared/imageDiffView'; import { ImageDiffView } from '@web/shared/imageDiffView'; -import { TestErrorView, TestScreenshotErrorView } from './testErrorView'; +import { CodeSnippet, TestErrorView, TestScreenshotErrorView } from './testErrorView'; import * as icons from './icons'; import './testResultView.css'; @@ -72,7 +72,7 @@ export const TestResultView: React.FC<{ result: TestResult, }> = ({ test, result }) => { const { screenshots, videos, traces, otherAttachments, diffs, errors, otherAttachmentAnchors, screenshotAnchors } = React.useMemo(() => { - const attachments = result.attachments; + const attachments = result.attachments.filter(a => !a.name.startsWith('_')); const screenshots = new Set(attachments.filter(a => a.contentType.startsWith('image/'))); const screenshotAnchors = [...screenshots].map(a => `attachment-${attachments.indexOf(a)}`); const videos = attachments.filter(a => a.contentType.startsWith('video/')); @@ -81,7 +81,7 @@ export const TestResultView: React.FC<{ [...screenshots, ...videos, ...traces].forEach(a => otherAttachments.delete(a)); const otherAttachmentAnchors = [...otherAttachments].map(a => `attachment-${attachments.indexOf(a)}`); const diffs = groupImageDiffs(screenshots, result); - const errors = classifyErrors(result.errors, diffs); + const errors = classifyErrors(result.errors, diffs, result.attachments); return { screenshots: [...screenshots], videos, traces, otherAttachments, diffs, errors, otherAttachmentAnchors, screenshotAnchors }; }, [result]); @@ -90,7 +90,7 @@ export const TestResultView: React.FC<{ {errors.map((error, index) => { if (error.type === 'screenshot') return ; - return ; + return ; })} } {!!result.steps.length && @@ -144,8 +144,8 @@ export const TestResultView: React.FC<{
; }; -function classifyErrors(testErrors: string[], diffs: ImageDiff[]) { - return testErrors.map(error => { +function classifyErrors(testErrors: string[], diffs: ImageDiff[], attachments: TestAttachment[]) { + return testErrors.map((error, i) => { const firstLine = error.split('\n')[0]; if (firstLine.includes('toHaveScreenshot') || firstLine.includes('toMatchSnapshot')) { const matchingDiff = diffs.find(diff => { @@ -164,7 +164,9 @@ function classifyErrors(testErrors: string[], diffs: ImageDiff[]) { return { type: 'screenshot', diff: matchingDiff, errorPrefix, errorSuffix }; } } - return { type: 'regular', error }; + + const prompt = attachments.find(a => a.name === `_prompt-${i}`)?.body; + return { type: 'regular', error, prompt }; }); } @@ -176,27 +178,14 @@ const StepTreeItem: React.FC<{ }> = ({ test, step, result, depth }) => { return {msToString(step.duration)} + {step.attachments.length > 0 && { evt.stopPropagation(); }}>{icons.attachment()}} {statusIcon(step.error || step.duration === -1 ? 'failed' : (step.skipped ? 'skipped' : 'passed'))} {step.title} {step.count > 1 && <> ✕ {step.count}} {step.location && — {step.location.file}:{step.location.line}} } loadChildren={step.steps.length || step.snippet ? () => { - const snippet = step.snippet ? [] : []; + const snippet = step.snippet ? [] : []; const steps = step.steps.map((s, i) => ); - const attachments = step.attachments.map(attachmentIndex => ( - - - {icons.attachment()}{result.attachments[attachmentIndex].name} - - - )); - return snippet.concat(steps, attachments); + return snippet.concat(steps); } : undefined} depth={depth}/>; }; diff --git a/packages/html-reporter/src/treeItem.css b/packages/html-reporter/src/treeItem.css index f37a759c2d4fa..b957d1ec5c032 100644 --- a/packages/html-reporter/src/treeItem.css +++ b/packages/html-reporter/src/treeItem.css @@ -25,11 +25,14 @@ cursor: pointer; } -.tree-item-title.selected { - text-decoration: underline var(--color-underlinenav-icon); - text-decoration-thickness: 1.5px; -} - .tree-item-body { min-height: 18px; } + +.yellow-flash { + animation: yellowflash-bg 2s; +} +@keyframes yellowflash-bg { + from { background: var(--color-attention-subtle); } + to { background: transparent; } +} diff --git a/packages/html-reporter/src/treeItem.tsx b/packages/html-reporter/src/treeItem.tsx index 926a398a053f7..7ae9b840f8968 100644 --- a/packages/html-reporter/src/treeItem.tsx +++ b/packages/html-reporter/src/treeItem.tsx @@ -25,12 +25,12 @@ export const TreeItem: React.FunctionComponent<{ onClick?: () => void, expandByDefault?: boolean, depth: number, - selected?: boolean, style?: React.CSSProperties, -}> = ({ title, loadChildren, onClick, expandByDefault, depth, selected, style }) => { + flash?: boolean +}> = ({ title, loadChildren, onClick, expandByDefault, depth, style, flash }) => { const [expanded, setExpanded] = React.useState(expandByDefault || false); - return
- { onClick?.(); setExpanded(!expanded); }} > + return
+ { onClick?.(); setExpanded(!expanded); }} > {loadChildren && !!expanded && icons.downArrow()} {loadChildren && !expanded && icons.rightArrow()} {!loadChildren && {icons.rightArrow()}} diff --git a/packages/html-reporter/tsconfig.json b/packages/html-reporter/tsconfig.json index 4fe82eab4eb1c..95a13e918d220 100644 --- a/packages/html-reporter/tsconfig.json +++ b/packages/html-reporter/tsconfig.json @@ -20,10 +20,12 @@ "@protocol/*": ["../protocol/src/*"], "@web/*": ["../web/src/*"], "@playwright/*": ["../playwright/src/*"], + "@recorder/*": ["../recorder/src/*"], + "@testIsomorphic/*": ["../playwright/src/isomorphic/*"], "playwright-core/lib/*": ["../playwright-core/src/*"], "playwright/lib/*": ["../playwright/src/*"], } }, - "include": ["src"], + "include": ["src", "../web/src"], "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/packages/html-reporter/vite.config.ts b/packages/html-reporter/vite.config.ts index bdde2574d59f9..f0032feb279e9 100644 --- a/packages/html-reporter/vite.config.ts +++ b/packages/html-reporter/vite.config.ts @@ -17,7 +17,7 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { bundle } from './bundle'; -import * as path from 'path'; +import path from 'path'; // https://vitejs.dev/config/ export default defineConfig({ diff --git a/packages/playwright-browser-chromium/package.json b/packages/playwright-browser-chromium/package.json index 909d5d326177c..f412f309b0c83 100644 --- a/packages/playwright-browser-chromium/package.json +++ b/packages/playwright-browser-chromium/package.json @@ -1,6 +1,6 @@ { "name": "@playwright/browser-chromium", - "version": "1.50.0-next", + "version": "1.51.1", "description": "Playwright package that automatically installs Chromium", "repository": { "type": "git", @@ -27,6 +27,6 @@ "install": "node install.js" }, "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" } } diff --git a/packages/playwright-browser-firefox/package.json b/packages/playwright-browser-firefox/package.json index 635cfd6811f0f..9ecf30b6e8bb0 100644 --- a/packages/playwright-browser-firefox/package.json +++ b/packages/playwright-browser-firefox/package.json @@ -1,6 +1,6 @@ { "name": "@playwright/browser-firefox", - "version": "1.50.0-next", + "version": "1.51.1", "description": "Playwright package that automatically installs Firefox", "repository": { "type": "git", @@ -27,6 +27,6 @@ "install": "node install.js" }, "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" } } diff --git a/packages/playwright-browser-webkit/package.json b/packages/playwright-browser-webkit/package.json index 61811e3684b83..851be8db874c7 100644 --- a/packages/playwright-browser-webkit/package.json +++ b/packages/playwright-browser-webkit/package.json @@ -1,6 +1,6 @@ { "name": "@playwright/browser-webkit", - "version": "1.50.0-next", + "version": "1.51.1", "description": "Playwright package that automatically installs WebKit", "repository": { "type": "git", @@ -27,6 +27,6 @@ "install": "node install.js" }, "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" } } diff --git a/packages/playwright-chromium/package.json b/packages/playwright-chromium/package.json index 22cabe176ce97..88b1613a5339e 100644 --- a/packages/playwright-chromium/package.json +++ b/packages/playwright-chromium/package.json @@ -1,6 +1,6 @@ { "name": "playwright-chromium", - "version": "1.50.0-next", + "version": "1.51.1", "description": "A high-level API to automate Chromium", "repository": { "type": "git", @@ -30,6 +30,6 @@ "install": "node install.js" }, "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" } } diff --git a/packages/playwright-client/index.d.ts b/packages/playwright-client/index.d.ts new file mode 100644 index 0000000000000..74906f0947068 --- /dev/null +++ b/packages/playwright-client/index.d.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Browser } from './types/types'; + +export * from './types/types'; + +export type Options = { + headless?: boolean; +}; + +export const connect: (wsEndpoint: string, browserName: string, options: Options) => Promise; diff --git a/utils/eslint-plugin-internal-playwright/index.js b/packages/playwright-client/index.js similarity index 82% rename from utils/eslint-plugin-internal-playwright/index.js rename to packages/playwright-client/index.js index 20deef8cc426e..227eee0fde3b0 100644 --- a/utils/eslint-plugin-internal-playwright/index.js +++ b/packages/playwright-client/index.js @@ -13,8 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -module.exports = { - rules: { - 'await-promise-in-class-returns': require('./rules/await-promise-in-class-returns'), - } -}; + +module.exports = require('./lib/index'); diff --git a/packages/playwright-client/index.mjs b/packages/playwright-client/index.mjs new file mode 100644 index 0000000000000..0332e501571ce --- /dev/null +++ b/packages/playwright-client/index.mjs @@ -0,0 +1,17 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { connect } from './index.js'; diff --git a/packages/playwright-client/package.json b/packages/playwright-client/package.json new file mode 100644 index 0000000000000..dc6baeffea812 --- /dev/null +++ b/packages/playwright-client/package.json @@ -0,0 +1,34 @@ +{ + "name": "@playwright/client", + "private": true, + "version": "0.0.0", + "description": "A thin client for Playwright", + "repository": { + "type": "git", + "url": "git+https://github.com/microsoft/playwright.git" + }, + "homepage": "https://playwright.dev", + "engines": { + "node": ">=18" + }, + "author": { + "name": "Microsoft Corporation" + }, + "license": "Apache-2.0", + "exports": { + ".": { + "types": "./index.d.ts", + "import": "./index.mjs", + "require": "./index.js", + "default": "./index.js" + }, + "./package.json": "./package.json" + }, + "scripts": { + "build": "esbuild ./src/index.ts --outdir=lib --format=cjs --bundle --platform=node --target=ES2019", + "watch": "esbuild ./src/index.ts --outdir=lib --format=cjs --bundle --platform=node --target=ES2019 --watch" + }, + "dependencies": { + "playwright-core": "1.51.1" + } +} diff --git a/packages/playwright-client/src/index.ts b/packages/playwright-client/src/index.ts new file mode 100644 index 0000000000000..48762e4e81f0d --- /dev/null +++ b/packages/playwright-client/src/index.ts @@ -0,0 +1,40 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the 'License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Connection } from '../../playwright-core/src/client/connection'; +import { webPlatform } from './webPlatform'; + +import type { Browser } from '../../playwright-core/src/client/browser'; + +export type Options = { + headless?: boolean; +}; + +export async function connect(wsEndpoint: string, browserName: string, options: Options): Promise { + const ws = new WebSocket(`${wsEndpoint}?browser=${browserName}&launch-options=${JSON.stringify(options)}`); + await new Promise((f, r) => { + ws.addEventListener('open', f); + ws.addEventListener('error', r); + }); + + const connection = new Connection(webPlatform); + connection.onmessage = message => ws.send(JSON.stringify(message)); + ws.addEventListener('message', message => connection.dispatch(JSON.parse(message.data))); + ws.addEventListener('close', () => connection.close()); + + const playwright = await connection.initializePlaywright(); + return playwright._preLaunchedBrowser(); +} diff --git a/packages/playwright-client/src/webPlatform.ts b/packages/playwright-client/src/webPlatform.ts new file mode 100644 index 0000000000000..e7d64817ecfe2 --- /dev/null +++ b/packages/playwright-client/src/webPlatform.ts @@ -0,0 +1,48 @@ +/* eslint-disable no-console */ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { emptyPlatform } from '../../playwright-core/src/client/platform'; + +import type { Platform } from '../../playwright-core/src/client/platform'; + +export const webPlatform: Platform = { + ...emptyPlatform, + + name: 'web', + + boxedStackPrefixes: () => [], + + calculateSha1: async (text: string) => { + const bytes = new TextEncoder().encode(text); + const hashBuffer = await window.crypto.subtle.digest('SHA-1', bytes); + return Array.from(new Uint8Array(hashBuffer), b => b.toString(16).padStart(2, '0')).join(''); + }, + + createGuid: () => { + return Array.from(window.crypto.getRandomValues(new Uint8Array(16)), b => b.toString(16).padStart(2, '0')).join(''); + }, + + isLogEnabled(name: 'api' | 'channel') { + return true; + }, + + log(name: 'api' | 'channel', message: string | Error | object) { + console.debug(name, message); + }, + + showInternalStackFrames: () => true, +}; diff --git a/packages/playwright-client/types/types.d.ts b/packages/playwright-client/types/types.d.ts new file mode 100644 index 0000000000000..033eed330460d --- /dev/null +++ b/packages/playwright-client/types/types.d.ts @@ -0,0 +1,22717 @@ +// This file is generated by /utils/generate_types/index.js +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ChildProcess } from 'child_process'; +import { Readable } from 'stream'; +import { ReadStream } from 'fs'; +import { Protocol } from './protocol'; +import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from './structs'; + +type PageWaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & { + state?: 'visible'|'attached'; +}; +type ElementHandleWaitForSelectorOptionsNotHidden = ElementHandleWaitForSelectorOptions & { + state?: 'visible'|'attached'; +}; + +/** + * Page provides methods to interact with a single tab in a [Browser](https://playwright.dev/docs/api/class-browser), + * or an [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. One + * [Browser](https://playwright.dev/docs/api/class-browser) instance might have multiple + * [Page](https://playwright.dev/docs/api/class-page) instances. + * + * This example creates a page, navigates it to a URL, and then saves a screenshot: + * + * ```js + * const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'. + * + * (async () => { + * const browser = await webkit.launch(); + * const context = await browser.newContext(); + * const page = await context.newPage(); + * await page.goto('https://example.com'); + * await page.screenshot({ path: 'screenshot.png' }); + * await browser.close(); + * })(); + * ``` + * + * The Page class emits various events (described below) which can be handled using any of Node's native + * [`EventEmitter`](https://nodejs.org/api/events.html#events_class_eventemitter) methods, such as `on`, `once` or + * `removeListener`. + * + * This example logs a message for a single page `load` event: + * + * ```js + * page.once('load', () => console.log('Page loaded!')); + * ``` + * + * To unsubscribe from events use the `removeListener` method: + * + * ```js + * function logRequest(interceptedRequest) { + * console.log('A request was made:', interceptedRequest.url()); + * } + * page.on('request', logRequest); + * // Sometime later... + * page.removeListener('request', logRequest); + * ``` + * + */ +export interface Page { + /** + * Returns the value of the + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-evaluate-option-expression) invocation. + * + * If the function passed to the + * [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate) returns a [Promise], + * then [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate) would wait for + * the promise to resolve and return its value. + * + * If the function passed to the + * [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate) returns a + * non-[Serializable] value, then + * [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate) resolves to + * `undefined`. Playwright also supports transferring some additional values that are not serializable by `JSON`: + * `-0`, `NaN`, `Infinity`, `-Infinity`. + * + * **Usage** + * + * Passing argument to [`pageFunction`](https://playwright.dev/docs/api/class-page#page-evaluate-option-expression): + * + * ```js + * const result = await page.evaluate(([x, y]) => { + * return Promise.resolve(x * y); + * }, [7, 8]); + * console.log(result); // prints "56" + * ``` + * + * A string can also be passed in instead of a function: + * + * ```js + * console.log(await page.evaluate('1 + 2')); // prints "3" + * const x = 10; + * console.log(await page.evaluate(`1 + ${x}`)); // prints "11" + * ``` + * + * [ElementHandle](https://playwright.dev/docs/api/class-elementhandle) instances can be passed as an argument to the + * [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate): + * + * ```js + * const bodyHandle = await page.evaluate('document.body'); + * const html = await page.evaluate(([body, suffix]) => + * body.innerHTML + suffix, [bodyHandle, 'hello'] + * ); + * await bodyHandle.dispose(); + * ``` + * + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-evaluate-option-expression). + */ + evaluate(pageFunction: PageFunction, arg: Arg): Promise; + /** + * Returns the value of the + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-evaluate-option-expression) invocation. + * + * If the function passed to the + * [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate) returns a [Promise], + * then [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate) would wait for + * the promise to resolve and return its value. + * + * If the function passed to the + * [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate) returns a + * non-[Serializable] value, then + * [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate) resolves to + * `undefined`. Playwright also supports transferring some additional values that are not serializable by `JSON`: + * `-0`, `NaN`, `Infinity`, `-Infinity`. + * + * **Usage** + * + * Passing argument to [`pageFunction`](https://playwright.dev/docs/api/class-page#page-evaluate-option-expression): + * + * ```js + * const result = await page.evaluate(([x, y]) => { + * return Promise.resolve(x * y); + * }, [7, 8]); + * console.log(result); // prints "56" + * ``` + * + * A string can also be passed in instead of a function: + * + * ```js + * console.log(await page.evaluate('1 + 2')); // prints "3" + * const x = 10; + * console.log(await page.evaluate(`1 + ${x}`)); // prints "11" + * ``` + * + * [ElementHandle](https://playwright.dev/docs/api/class-elementhandle) instances can be passed as an argument to the + * [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate): + * + * ```js + * const bodyHandle = await page.evaluate('document.body'); + * const html = await page.evaluate(([body, suffix]) => + * body.innerHTML + suffix, [bodyHandle, 'hello'] + * ); + * await bodyHandle.dispose(); + * ``` + * + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-evaluate-option-expression). + */ + evaluate(pageFunction: PageFunction, arg?: any): Promise; + + /** + * Returns the value of the + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-evaluate-handle-option-expression) invocation as a + * [JSHandle](https://playwright.dev/docs/api/class-jshandle). + * + * The only difference between + * [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate) and + * [page.evaluateHandle(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate-handle) is that + * [page.evaluateHandle(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate-handle) returns + * [JSHandle](https://playwright.dev/docs/api/class-jshandle). + * + * If the function passed to the + * [page.evaluateHandle(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate-handle) returns + * a [Promise], then + * [page.evaluateHandle(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate-handle) would + * wait for the promise to resolve and return its value. + * + * **Usage** + * + * ```js + * // Handle for the window object. + * const aWindowHandle = await page.evaluateHandle(() => Promise.resolve(window)); + * ``` + * + * A string can also be passed in instead of a function: + * + * ```js + * const aHandle = await page.evaluateHandle('document'); // Handle for the 'document' + * ``` + * + * [JSHandle](https://playwright.dev/docs/api/class-jshandle) instances can be passed as an argument to the + * [page.evaluateHandle(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate-handle): + * + * ```js + * const aHandle = await page.evaluateHandle(() => document.body); + * const resultHandle = await page.evaluateHandle(body => body.innerHTML, aHandle); + * console.log(await resultHandle.jsonValue()); + * await resultHandle.dispose(); + * ``` + * + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-evaluate-handle-option-expression). + */ + evaluateHandle(pageFunction: PageFunction, arg: Arg): Promise>; + /** + * Returns the value of the + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-evaluate-handle-option-expression) invocation as a + * [JSHandle](https://playwright.dev/docs/api/class-jshandle). + * + * The only difference between + * [page.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate) and + * [page.evaluateHandle(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate-handle) is that + * [page.evaluateHandle(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate-handle) returns + * [JSHandle](https://playwright.dev/docs/api/class-jshandle). + * + * If the function passed to the + * [page.evaluateHandle(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate-handle) returns + * a [Promise], then + * [page.evaluateHandle(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate-handle) would + * wait for the promise to resolve and return its value. + * + * **Usage** + * + * ```js + * // Handle for the window object. + * const aWindowHandle = await page.evaluateHandle(() => Promise.resolve(window)); + * ``` + * + * A string can also be passed in instead of a function: + * + * ```js + * const aHandle = await page.evaluateHandle('document'); // Handle for the 'document' + * ``` + * + * [JSHandle](https://playwright.dev/docs/api/class-jshandle) instances can be passed as an argument to the + * [page.evaluateHandle(pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-evaluate-handle): + * + * ```js + * const aHandle = await page.evaluateHandle(() => document.body); + * const resultHandle = await page.evaluateHandle(body => body.innerHTML, aHandle); + * console.log(await resultHandle.jsonValue()); + * await resultHandle.dispose(); + * ``` + * + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-evaluate-handle-option-expression). + */ + evaluateHandle(pageFunction: PageFunction, arg?: any): Promise>; + + /** + * Adds a script which would be evaluated in one of the following scenarios: + * - Whenever the page is navigated. + * - Whenever the child frame is attached or navigated. In this case, the script is evaluated in the context of the + * newly attached frame. + * + * The script is evaluated after the document was created but before any of its scripts were run. This is useful to + * amend the JavaScript environment, e.g. to seed `Math.random`. + * + * **Usage** + * + * An example of overriding `Math.random` before the page loads: + * + * ```js + * // preload.js + * Math.random = () => 42; + * ``` + * + * ```js + * // In your playwright script, assuming the preload.js file is in same directory + * await page.addInitScript({ path: './preload.js' }); + * ``` + * + * ```js + * await page.addInitScript(mock => { + * window.mock = mock; + * }, mock); + * ``` + * + * **NOTE** The order of evaluation of multiple scripts installed via + * [browserContext.addInitScript(script[, arg])](https://playwright.dev/docs/api/class-browsercontext#browser-context-add-init-script) + * and [page.addInitScript(script[, arg])](https://playwright.dev/docs/api/class-page#page-add-init-script) is not + * defined. + * + * @param script Script to be evaluated in the page. + * @param arg Optional argument to pass to + * [`script`](https://playwright.dev/docs/api/class-page#page-add-init-script-option-script) (only supported when + * passing a function). + */ + addInitScript(script: PageFunction | { path?: string, content?: string }, arg?: Arg): Promise; + + /** + * **NOTE** Use locator-based [page.locator(selector[, options])](https://playwright.dev/docs/api/class-page#page-locator) + * instead. Read more about [locators](https://playwright.dev/docs/locators). + * + * The method finds an element matching the specified selector within the page. If no elements match the selector, the + * return value resolves to `null`. To wait for an element on the page, use + * [locator.waitFor([options])](https://playwright.dev/docs/api/class-locator#locator-wait-for). + * @param selector A selector to query for. + * @param options + */ + $(selector: K, options?: { strict: boolean }): Promise | null>; + /** + * **NOTE** Use locator-based [page.locator(selector[, options])](https://playwright.dev/docs/api/class-page#page-locator) + * instead. Read more about [locators](https://playwright.dev/docs/locators). + * + * The method finds an element matching the specified selector within the page. If no elements match the selector, the + * return value resolves to `null`. To wait for an element on the page, use + * [locator.waitFor([options])](https://playwright.dev/docs/api/class-locator#locator-wait-for). + * @param selector A selector to query for. + * @param options + */ + $(selector: string, options?: { strict: boolean }): Promise | null>; + + /** + * **NOTE** Use locator-based [page.locator(selector[, options])](https://playwright.dev/docs/api/class-page#page-locator) + * instead. Read more about [locators](https://playwright.dev/docs/locators). + * + * The method finds all elements matching the specified selector within the page. If no elements match the selector, + * the return value resolves to `[]`. + * @param selector A selector to query for. + */ + $$(selector: K): Promise[]>; + /** + * **NOTE** Use locator-based [page.locator(selector[, options])](https://playwright.dev/docs/api/class-page#page-locator) + * instead. Read more about [locators](https://playwright.dev/docs/locators). + * + * The method finds all elements matching the specified selector within the page. If no elements match the selector, + * the return value resolves to `[]`. + * @param selector A selector to query for. + */ + $$(selector: string): Promise[]>; + + /** + * **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests. + * Use + * [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate), + * other [Locator](https://playwright.dev/docs/api/class-locator) helper methods or web-first assertions instead. + * + * The method finds an element matching the specified selector within the page and passes it as a first argument to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). If no + * elements match the selector, the method throws an error. Returns the value of + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). + * + * If [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression) returns a + * [Promise], then + * [page.$eval(selector, pageFunction[, arg, options])](https://playwright.dev/docs/api/class-page#page-eval-on-selector) + * would wait for the promise to resolve and return its value. + * + * **Usage** + * + * ```js + * const searchValue = await page.$eval('#search', el => el.value); + * const preloadHref = await page.$eval('link[rel=preload]', el => el.href); + * const html = await page.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello'); + * // In TypeScript, this example requires an explicit type annotation (HTMLLinkElement) on el: + * const preloadHrefTS = await page.$eval('link[rel=preload]', (el: HTMLLinkElement) => el.href); + * ``` + * + * @param selector A selector to query for. + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). + * @param options + */ + $eval(selector: K, pageFunction: PageFunctionOn, arg: Arg): Promise; + /** + * **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests. + * Use + * [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate), + * other [Locator](https://playwright.dev/docs/api/class-locator) helper methods or web-first assertions instead. + * + * The method finds an element matching the specified selector within the page and passes it as a first argument to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). If no + * elements match the selector, the method throws an error. Returns the value of + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). + * + * If [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression) returns a + * [Promise], then + * [page.$eval(selector, pageFunction[, arg, options])](https://playwright.dev/docs/api/class-page#page-eval-on-selector) + * would wait for the promise to resolve and return its value. + * + * **Usage** + * + * ```js + * const searchValue = await page.$eval('#search', el => el.value); + * const preloadHref = await page.$eval('link[rel=preload]', el => el.href); + * const html = await page.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello'); + * // In TypeScript, this example requires an explicit type annotation (HTMLLinkElement) on el: + * const preloadHrefTS = await page.$eval('link[rel=preload]', (el: HTMLLinkElement) => el.href); + * ``` + * + * @param selector A selector to query for. + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). + * @param options + */ + $eval(selector: string, pageFunction: PageFunctionOn, arg: Arg): Promise; + /** + * **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests. + * Use + * [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate), + * other [Locator](https://playwright.dev/docs/api/class-locator) helper methods or web-first assertions instead. + * + * The method finds an element matching the specified selector within the page and passes it as a first argument to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). If no + * elements match the selector, the method throws an error. Returns the value of + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). + * + * If [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression) returns a + * [Promise], then + * [page.$eval(selector, pageFunction[, arg, options])](https://playwright.dev/docs/api/class-page#page-eval-on-selector) + * would wait for the promise to resolve and return its value. + * + * **Usage** + * + * ```js + * const searchValue = await page.$eval('#search', el => el.value); + * const preloadHref = await page.$eval('link[rel=preload]', el => el.href); + * const html = await page.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello'); + * // In TypeScript, this example requires an explicit type annotation (HTMLLinkElement) on el: + * const preloadHrefTS = await page.$eval('link[rel=preload]', (el: HTMLLinkElement) => el.href); + * ``` + * + * @param selector A selector to query for. + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). + * @param options + */ + $eval(selector: K, pageFunction: PageFunctionOn, arg?: any): Promise; + /** + * **NOTE** This method does not wait for the element to pass actionability checks and therefore can lead to the flaky tests. + * Use + * [locator.evaluate(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-locator#locator-evaluate), + * other [Locator](https://playwright.dev/docs/api/class-locator) helper methods or web-first assertions instead. + * + * The method finds an element matching the specified selector within the page and passes it as a first argument to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). If no + * elements match the selector, the method throws an error. Returns the value of + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). + * + * If [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression) returns a + * [Promise], then + * [page.$eval(selector, pageFunction[, arg, options])](https://playwright.dev/docs/api/class-page#page-eval-on-selector) + * would wait for the promise to resolve and return its value. + * + * **Usage** + * + * ```js + * const searchValue = await page.$eval('#search', el => el.value); + * const preloadHref = await page.$eval('link[rel=preload]', el => el.href); + * const html = await page.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello'); + * // In TypeScript, this example requires an explicit type annotation (HTMLLinkElement) on el: + * const preloadHrefTS = await page.$eval('link[rel=preload]', (el: HTMLLinkElement) => el.href); + * ``` + * + * @param selector A selector to query for. + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-option-expression). + * @param options + */ + $eval(selector: string, pageFunction: PageFunctionOn, arg?: any): Promise; + + /** + * **NOTE** In most cases, + * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all), + * other [Locator](https://playwright.dev/docs/api/class-locator) helper methods and web-first assertions do a better + * job. + * + * The method finds all elements matching the specified selector within the page and passes an array of matched + * elements as a first argument to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression). Returns + * the result of + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression) + * invocation. + * + * If [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression) returns + * a [Promise], then + * [page.$$eval(selector, pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all) + * would wait for the promise to resolve and return its value. + * + * **Usage** + * + * ```js + * const divCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10); + * ``` + * + * @param selector A selector to query for. + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression). + */ + $$eval(selector: K, pageFunction: PageFunctionOn, arg: Arg): Promise; + /** + * **NOTE** In most cases, + * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all), + * other [Locator](https://playwright.dev/docs/api/class-locator) helper methods and web-first assertions do a better + * job. + * + * The method finds all elements matching the specified selector within the page and passes an array of matched + * elements as a first argument to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression). Returns + * the result of + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression) + * invocation. + * + * If [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression) returns + * a [Promise], then + * [page.$$eval(selector, pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all) + * would wait for the promise to resolve and return its value. + * + * **Usage** + * + * ```js + * const divCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10); + * ``` + * + * @param selector A selector to query for. + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression). + */ + $$eval(selector: string, pageFunction: PageFunctionOn, arg: Arg): Promise; + /** + * **NOTE** In most cases, + * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all), + * other [Locator](https://playwright.dev/docs/api/class-locator) helper methods and web-first assertions do a better + * job. + * + * The method finds all elements matching the specified selector within the page and passes an array of matched + * elements as a first argument to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression). Returns + * the result of + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression) + * invocation. + * + * If [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression) returns + * a [Promise], then + * [page.$$eval(selector, pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all) + * would wait for the promise to resolve and return its value. + * + * **Usage** + * + * ```js + * const divCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10); + * ``` + * + * @param selector A selector to query for. + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression). + */ + $$eval(selector: K, pageFunction: PageFunctionOn, arg?: any): Promise; + /** + * **NOTE** In most cases, + * [locator.evaluateAll(pageFunction[, arg])](https://playwright.dev/docs/api/class-locator#locator-evaluate-all), + * other [Locator](https://playwright.dev/docs/api/class-locator) helper methods and web-first assertions do a better + * job. + * + * The method finds all elements matching the specified selector within the page and passes an array of matched + * elements as a first argument to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression). Returns + * the result of + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression) + * invocation. + * + * If [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression) returns + * a [Promise], then + * [page.$$eval(selector, pageFunction[, arg])](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all) + * would wait for the promise to resolve and return its value. + * + * **Usage** + * + * ```js + * const divCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10); + * ``` + * + * @param selector A selector to query for. + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-eval-on-selector-all-option-expression). + */ + $$eval(selector: string, pageFunction: PageFunctionOn, arg?: any): Promise; + + /** + * Returns when the + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-wait-for-function-option-expression) returns a + * truthy value. It resolves to a JSHandle of the truthy value. + * + * **Usage** + * + * The + * [page.waitForFunction(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-page#page-wait-for-function) + * can be used to observe viewport size change: + * + * ```js + * const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'. + * + * (async () => { + * const browser = await webkit.launch(); + * const page = await browser.newPage(); + * const watchDog = page.waitForFunction(() => window.innerWidth < 100); + * await page.setViewportSize({ width: 50, height: 50 }); + * await watchDog; + * await browser.close(); + * })(); + * ``` + * + * To pass an argument to the predicate of + * [page.waitForFunction(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-page#page-wait-for-function) + * function: + * + * ```js + * const selector = '.foo'; + * await page.waitForFunction(selector => !!document.querySelector(selector), selector); + * ``` + * + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-wait-for-function-option-expression). + * @param options + */ + waitForFunction(pageFunction: PageFunction, arg: Arg, options?: PageWaitForFunctionOptions): Promise>; + /** + * Returns when the + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-wait-for-function-option-expression) returns a + * truthy value. It resolves to a JSHandle of the truthy value. + * + * **Usage** + * + * The + * [page.waitForFunction(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-page#page-wait-for-function) + * can be used to observe viewport size change: + * + * ```js + * const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'. + * + * (async () => { + * const browser = await webkit.launch(); + * const page = await browser.newPage(); + * const watchDog = page.waitForFunction(() => window.innerWidth < 100); + * await page.setViewportSize({ width: 50, height: 50 }); + * await watchDog; + * await browser.close(); + * })(); + * ``` + * + * To pass an argument to the predicate of + * [page.waitForFunction(pageFunction[, arg, options])](https://playwright.dev/docs/api/class-page#page-wait-for-function) + * function: + * + * ```js + * const selector = '.foo'; + * await page.waitForFunction(selector => !!document.querySelector(selector), selector); + * ``` + * + * @param pageFunction Function to be evaluated in the page context. + * @param arg Optional argument to pass to + * [`pageFunction`](https://playwright.dev/docs/api/class-page#page-wait-for-function-option-expression). + * @param options + */ + waitForFunction(pageFunction: PageFunction, arg?: any, options?: PageWaitForFunctionOptions): Promise>; + + /** + * **NOTE** Use web assertions that assert visibility or a locator-based + * [locator.waitFor([options])](https://playwright.dev/docs/api/class-locator#locator-wait-for) instead. Read more + * about [locators](https://playwright.dev/docs/locators). + * + * Returns when element specified by selector satisfies + * [`state`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-state) option. Returns `null` if + * waiting for `hidden` or `detached`. + * + * **NOTE** Playwright automatically waits for element to be ready before performing an action. Using + * [Locator](https://playwright.dev/docs/api/class-locator) objects and web-first assertions makes the code + * wait-for-selector-free. + * + * Wait for the [`selector`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-selector) to + * satisfy [`state`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-state) option (either + * appear/disappear from dom, or become visible/hidden). If at the moment of calling the method + * [`selector`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-selector) already satisfies + * the condition, the method will return immediately. If the selector doesn't satisfy the condition for the + * [`timeout`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-timeout) milliseconds, the + * function will throw. + * + * **Usage** + * + * This method works across navigations: + * + * ```js + * const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'. + * + * (async () => { + * const browser = await chromium.launch(); + * const page = await browser.newPage(); + * for (const currentURL of ['https://google.com', 'https://bbc.com']) { + * await page.goto(currentURL); + * const element = await page.waitForSelector('img'); + * console.log('Loaded image: ' + await element.getAttribute('src')); + * } + * await browser.close(); + * })(); + * ``` + * + * @param selector A selector to query for. + * @param options + */ + waitForSelector(selector: K, options?: PageWaitForSelectorOptionsNotHidden): Promise>; + /** + * **NOTE** Use web assertions that assert visibility or a locator-based + * [locator.waitFor([options])](https://playwright.dev/docs/api/class-locator#locator-wait-for) instead. Read more + * about [locators](https://playwright.dev/docs/locators). + * + * Returns when element specified by selector satisfies + * [`state`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-state) option. Returns `null` if + * waiting for `hidden` or `detached`. + * + * **NOTE** Playwright automatically waits for element to be ready before performing an action. Using + * [Locator](https://playwright.dev/docs/api/class-locator) objects and web-first assertions makes the code + * wait-for-selector-free. + * + * Wait for the [`selector`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-selector) to + * satisfy [`state`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-state) option (either + * appear/disappear from dom, or become visible/hidden). If at the moment of calling the method + * [`selector`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-selector) already satisfies + * the condition, the method will return immediately. If the selector doesn't satisfy the condition for the + * [`timeout`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-timeout) milliseconds, the + * function will throw. + * + * **Usage** + * + * This method works across navigations: + * + * ```js + * const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'. + * + * (async () => { + * const browser = await chromium.launch(); + * const page = await browser.newPage(); + * for (const currentURL of ['https://google.com', 'https://bbc.com']) { + * await page.goto(currentURL); + * const element = await page.waitForSelector('img'); + * console.log('Loaded image: ' + await element.getAttribute('src')); + * } + * await browser.close(); + * })(); + * ``` + * + * @param selector A selector to query for. + * @param options + */ + waitForSelector(selector: string, options?: PageWaitForSelectorOptionsNotHidden): Promise>; + /** + * **NOTE** Use web assertions that assert visibility or a locator-based + * [locator.waitFor([options])](https://playwright.dev/docs/api/class-locator#locator-wait-for) instead. Read more + * about [locators](https://playwright.dev/docs/locators). + * + * Returns when element specified by selector satisfies + * [`state`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-state) option. Returns `null` if + * waiting for `hidden` or `detached`. + * + * **NOTE** Playwright automatically waits for element to be ready before performing an action. Using + * [Locator](https://playwright.dev/docs/api/class-locator) objects and web-first assertions makes the code + * wait-for-selector-free. + * + * Wait for the [`selector`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-selector) to + * satisfy [`state`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-state) option (either + * appear/disappear from dom, or become visible/hidden). If at the moment of calling the method + * [`selector`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-selector) already satisfies + * the condition, the method will return immediately. If the selector doesn't satisfy the condition for the + * [`timeout`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-timeout) milliseconds, the + * function will throw. + * + * **Usage** + * + * This method works across navigations: + * + * ```js + * const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'. + * + * (async () => { + * const browser = await chromium.launch(); + * const page = await browser.newPage(); + * for (const currentURL of ['https://google.com', 'https://bbc.com']) { + * await page.goto(currentURL); + * const element = await page.waitForSelector('img'); + * console.log('Loaded image: ' + await element.getAttribute('src')); + * } + * await browser.close(); + * })(); + * ``` + * + * @param selector A selector to query for. + * @param options + */ + waitForSelector(selector: K, options: PageWaitForSelectorOptions): Promise | null>; + /** + * **NOTE** Use web assertions that assert visibility or a locator-based + * [locator.waitFor([options])](https://playwright.dev/docs/api/class-locator#locator-wait-for) instead. Read more + * about [locators](https://playwright.dev/docs/locators). + * + * Returns when element specified by selector satisfies + * [`state`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-state) option. Returns `null` if + * waiting for `hidden` or `detached`. + * + * **NOTE** Playwright automatically waits for element to be ready before performing an action. Using + * [Locator](https://playwright.dev/docs/api/class-locator) objects and web-first assertions makes the code + * wait-for-selector-free. + * + * Wait for the [`selector`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-selector) to + * satisfy [`state`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-state) option (either + * appear/disappear from dom, or become visible/hidden). If at the moment of calling the method + * [`selector`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-selector) already satisfies + * the condition, the method will return immediately. If the selector doesn't satisfy the condition for the + * [`timeout`](https://playwright.dev/docs/api/class-page#page-wait-for-selector-option-timeout) milliseconds, the + * function will throw. + * + * **Usage** + * + * This method works across navigations: + * + * ```js + * const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'. + * + * (async () => { + * const browser = await chromium.launch(); + * const page = await browser.newPage(); + * for (const currentURL of ['https://google.com', 'https://bbc.com']) { + * await page.goto(currentURL); + * const element = await page.waitForSelector('img'); + * console.log('Loaded image: ' + await element.getAttribute('src')); + * } + * await browser.close(); + * })(); + * ``` + * + * @param selector A selector to query for. + * @param options + */ + waitForSelector(selector: string, options: PageWaitForSelectorOptions): Promise>; + + /** + * The method adds a function called + * [`name`](https://playwright.dev/docs/api/class-page#page-expose-binding-option-name) on the `window` object of + * every frame in this page. When called, the function executes + * [`callback`](https://playwright.dev/docs/api/class-page#page-expose-binding-option-callback) and returns a + * [Promise] which resolves to the return value of + * [`callback`](https://playwright.dev/docs/api/class-page#page-expose-binding-option-callback). If the + * [`callback`](https://playwright.dev/docs/api/class-page#page-expose-binding-option-callback) returns a [Promise], + * it will be awaited. + * + * The first argument of the + * [`callback`](https://playwright.dev/docs/api/class-page#page-expose-binding-option-callback) function contains + * information about the caller: `{ browserContext: BrowserContext, page: Page, frame: Frame }`. + * + * See + * [browserContext.exposeBinding(name, callback[, options])](https://playwright.dev/docs/api/class-browsercontext#browser-context-expose-binding) + * for the context-wide version. + * + * **NOTE** Functions installed via + * [page.exposeBinding(name, callback[, options])](https://playwright.dev/docs/api/class-page#page-expose-binding) + * survive navigations. + * + * **Usage** + * + * An example of exposing page URL to all frames in a page: + * + * ```js + * const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'. + * + * (async () => { + * const browser = await webkit.launch({ headless: false }); + * const context = await browser.newContext(); + * const page = await context.newPage(); + * await page.exposeBinding('pageURL', ({ page }) => page.url()); + * await page.setContent(` + * + * + *
+ * `); + * await page.click('button'); + * })(); + * ``` + * + * @param name Name of the function on the window object. + * @param callback Callback function that will be called in the Playwright's context. + * @param options + */ + exposeBinding(name: string, playwrightBinding: (source: BindingSource, arg: JSHandle) => any, options: { handle: true }): Promise; + /** + * The method adds a function called + * [`name`](https://playwright.dev/docs/api/class-page#page-expose-binding-option-name) on the `window` object of + * every frame in this page. When called, the function executes + * [`callback`](https://playwright.dev/docs/api/class-page#page-expose-binding-option-callback) and returns a + * [Promise] which resolves to the return value of + * [`callback`](https://playwright.dev/docs/api/class-page#page-expose-binding-option-callback). If the + * [`callback`](https://playwright.dev/docs/api/class-page#page-expose-binding-option-callback) returns a [Promise], + * it will be awaited. + * + * The first argument of the + * [`callback`](https://playwright.dev/docs/api/class-page#page-expose-binding-option-callback) function contains + * information about the caller: `{ browserContext: BrowserContext, page: Page, frame: Frame }`. + * + * See + * [browserContext.exposeBinding(name, callback[, options])](https://playwright.dev/docs/api/class-browsercontext#browser-context-expose-binding) + * for the context-wide version. + * + * **NOTE** Functions installed via + * [page.exposeBinding(name, callback[, options])](https://playwright.dev/docs/api/class-page#page-expose-binding) + * survive navigations. + * + * **Usage** + * + * An example of exposing page URL to all frames in a page: + * + * ```js + * const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'. + * + * (async () => { + * const browser = await webkit.launch({ headless: false }); + * const context = await browser.newContext(); + * const page = await context.newPage(); + * await page.exposeBinding('pageURL', ({ page }) => page.url()); + * await page.setContent(` + * + * + *
+ * `); + * await page.click('button'); + * })(); + * ``` + * + * @param name Name of the function on the window object. + * @param callback Callback function that will be called in the Playwright's context. + * @param options + */ + exposeBinding(name: string, playwrightBinding: (source: BindingSource, ...args: any[]) => any, options?: { handle?: boolean }): Promise; + + /** + * Removes all the listeners of the given type (or all registered listeners if no type given). Allows to wait for + * async listeners to complete or to ignore subsequent errors from these listeners. + * + * **Usage** + * + * ```js + * page.on('request', async request => { + * const response = await request.response(); + * const body = await response.body(); + * console.log(body.byteLength); + * }); + * await page.goto('https://playwright.dev', { waitUntil: 'domcontentloaded' }); + * // Waits for all the reported 'request' events to resolve. + * await page.removeAllListeners('request', { behavior: 'wait' }); + * ``` + * + * @param type + * @param options + */ + removeAllListeners(type?: string): this; + /** + * Removes all the listeners of the given type (or all registered listeners if no type given). Allows to wait for + * async listeners to complete or to ignore subsequent errors from these listeners. + * + * **Usage** + * + * ```js + * page.on('request', async request => { + * const response = await request.response(); + * const body = await response.body(); + * console.log(body.byteLength); + * }); + * await page.goto('https://playwright.dev', { waitUntil: 'domcontentloaded' }); + * // Waits for all the reported 'request' events to resolve. + * await page.removeAllListeners('request', { behavior: 'wait' }); + * ``` + * + * @param type + * @param options + */ + removeAllListeners(type: string | undefined, options: { + /** + * Specifies whether to wait for already running listeners and what to do if they throw errors: + * - `'default'` - do not wait for current listener calls (if any) to finish, if the listener throws, it may result in unhandled error + * - `'wait'` - wait for current listener calls (if any) to finish + * - `'ignoreErrors'` - do not wait for current listener calls (if any) to finish, all errors thrown by the listeners after removal are silently caught + */ + behavior?: 'wait'|'ignoreErrors'|'default' + }): Promise; + /** + * Emitted when the page closes. + */ + on(event: 'close', listener: (page: Page) => any): this; + + /** + * Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. + * + * The arguments passed into `console.log` are available on the + * [ConsoleMessage](https://playwright.dev/docs/api/class-consolemessage) event handler argument. + * + * **Usage** + * + * ```js + * page.on('console', async msg => { + * const values = []; + * for (const arg of msg.args()) + * values.push(await arg.jsonValue()); + * console.log(...values); + * }); + * await page.evaluate(() => console.log('hello', 5, { foo: 'bar' })); + * ``` + * + */ + on(event: 'console', listener: (consoleMessage: ConsoleMessage) => any): this; + + /** + * Emitted when the page crashes. Browser pages might crash if they try to allocate too much memory. When the page + * crashes, ongoing and subsequent operations will throw. + * + * The most common way to deal with crashes is to catch an exception: + * + * ```js + * try { + * // Crash might happen during a click. + * await page.click('button'); + * // Or while waiting for an event. + * await page.waitForEvent('popup'); + * } catch (e) { + * // When the page crashes, exception message contains 'crash'. + * } + * ``` + * + */ + on(event: 'crash', listener: (page: Page) => any): this; + + /** + * Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, `confirm` or `beforeunload`. Listener **must** + * either [dialog.accept([promptText])](https://playwright.dev/docs/api/class-dialog#dialog-accept) or + * [dialog.dismiss()](https://playwright.dev/docs/api/class-dialog#dialog-dismiss) the dialog - otherwise the page + * will [freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking) waiting for the + * dialog, and actions like click will never finish. + * + * **Usage** + * + * ```js + * page.on('dialog', dialog => dialog.accept()); + * ``` + * + * **NOTE** When no [page.on('dialog')](https://playwright.dev/docs/api/class-page#page-event-dialog) or + * [browserContext.on('dialog')](https://playwright.dev/docs/api/class-browsercontext#browser-context-event-dialog) + * listeners are present, all dialogs are automatically dismissed. + * + */ + on(event: 'dialog', listener: (dialog: Dialog) => any): this; + + /** + * Emitted when the JavaScript + * [`DOMContentLoaded`](https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded) event is dispatched. + */ + on(event: 'domcontentloaded', listener: (page: Page) => any): this; + + /** + * Emitted when attachment download started. User can access basic file operations on downloaded content via the + * passed [Download](https://playwright.dev/docs/api/class-download) instance. + */ + on(event: 'download', listener: (download: Download) => any): this; + + /** + * Emitted when a file chooser is supposed to appear, such as after clicking the ``. Playwright can + * respond to it via setting the input files using + * [fileChooser.setFiles(files[, options])](https://playwright.dev/docs/api/class-filechooser#file-chooser-set-files) + * that can be uploaded after that. + * + * ```js + * page.on('filechooser', async fileChooser => { + * await fileChooser.setFiles(path.join(__dirname, '/tmp/myfile.pdf')); + * }); + * ``` + * + */ + on(event: 'filechooser', listener: (fileChooser: FileChooser) => any): this; + + /** + * Emitted when a frame is attached. + */ + on(event: 'frameattached', listener: (frame: Frame) => any): this; + + /** + * Emitted when a frame is detached. + */ + on(event: 'framedetached', listener: (frame: Frame) => any): this; + + /** + * Emitted when a frame is navigated to a new url. + */ + on(event: 'framenavigated', listener: (frame: Frame) => any): this; + + /** + * Emitted when the JavaScript [`load`](https://developer.mozilla.org/en-US/docs/Web/Events/load) event is dispatched. + */ + on(event: 'load', listener: (page: Page) => any): this; + + /** + * Emitted when an uncaught exception happens within the page. + * + * ```js + * // Log all uncaught errors to the terminal + * page.on('pageerror', exception => { + * console.log(`Uncaught exception: "${exception}"`); + * }); + * + * // Navigate to a page with an exception. + * await page.goto('data:text/html,'); + * ``` + * + */ + on(event: 'pageerror', listener: (error: Error) => any): this; + + /** + * Emitted when the page opens a new tab or window. This event is emitted in addition to the + * [browserContext.on('page')](https://playwright.dev/docs/api/class-browsercontext#browser-context-event-page), but + * only for popups relevant to this page. + * + * The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a + * popup with `window.open('http://example.com')`, this event will fire when the network request to + * "http://example.com" is done and its response has started loading in the popup. If you would like to route/listen + * to this network request, use + * [browserContext.route(url, handler[, options])](https://playwright.dev/docs/api/class-browsercontext#browser-context-route) + * and + * [browserContext.on('request')](https://playwright.dev/docs/api/class-browsercontext#browser-context-event-request) + * respectively instead of similar methods on the [Page](https://playwright.dev/docs/api/class-page). + * + * ```js + * // Start waiting for popup before clicking. Note no await. + * const popupPromise = page.waitForEvent('popup'); + * await page.getByText('open the popup').click(); + * const popup = await popupPromise; + * console.log(await popup.evaluate('location.href')); + * ``` + * + * **NOTE** Use + * [page.waitForLoadState([state, options])](https://playwright.dev/docs/api/class-page#page-wait-for-load-state) to + * wait until the page gets to a particular state (you should not need it in most cases). + * + */ + on(event: 'popup', listener: (page: Page) => any): this; + + /** + * Emitted when a page issues a request. The [request] object is read-only. In order to intercept and mutate requests, + * see [page.route(url, handler[, options])](https://playwright.dev/docs/api/class-page#page-route) or + * [browserContext.route(url, handler[, options])](https://playwright.dev/docs/api/class-browsercontext#browser-context-route). + */ + on(event: 'request', listener: (request: Request) => any): this; + + /** + * Emitted when a request fails, for example by timing out. + * + * ```js + * page.on('requestfailed', request => { + * console.log(request.url() + ' ' + request.failure().errorText); + * }); + * ``` + * + * **NOTE** HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request + * will complete with + * [page.on('requestfinished')](https://playwright.dev/docs/api/class-page#page-event-request-finished) event and not + * with [page.on('requestfailed')](https://playwright.dev/docs/api/class-page#page-event-request-failed). A request + * will only be considered failed when the client cannot get an HTTP response from the server, e.g. due to network + * error net::ERR_FAILED. + * + */ + on(event: 'requestfailed', listener: (request: Request) => any): this; + + /** + * Emitted when a request finishes successfully after downloading the response body. For a successful response, the + * sequence of events is `request`, `response` and `requestfinished`. + */ + on(event: 'requestfinished', listener: (request: Request) => any): this; + + /** + * Emitted when [response] status and headers are received for a request. For a successful response, the sequence of + * events is `request`, `response` and `requestfinished`. + */ + on(event: 'response', listener: (response: Response) => any): this; + + /** + * Emitted when [WebSocket](https://playwright.dev/docs/api/class-websocket) request is sent. + */ + on(event: 'websocket', listener: (webSocket: WebSocket) => any): this; + + /** + * Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is spawned + * by the page. + */ + on(event: 'worker', listener: (worker: Worker) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'close', listener: (page: Page) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'console', listener: (consoleMessage: ConsoleMessage) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'crash', listener: (page: Page) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'dialog', listener: (dialog: Dialog) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'domcontentloaded', listener: (page: Page) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'download', listener: (download: Download) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'filechooser', listener: (fileChooser: FileChooser) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'frameattached', listener: (frame: Frame) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'framedetached', listener: (frame: Frame) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'framenavigated', listener: (frame: Frame) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'load', listener: (page: Page) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'pageerror', listener: (error: Error) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'popup', listener: (page: Page) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'request', listener: (request: Request) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'requestfailed', listener: (request: Request) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'requestfinished', listener: (request: Request) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'response', listener: (response: Response) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'websocket', listener: (webSocket: WebSocket) => any): this; + + /** + * Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event. + */ + once(event: 'worker', listener: (worker: Worker) => any): this; + + /** + * Emitted when the page closes. + */ + addListener(event: 'close', listener: (page: Page) => any): this; + + /** + * Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. + * + * The arguments passed into `console.log` are available on the + * [ConsoleMessage](https://playwright.dev/docs/api/class-consolemessage) event handler argument. + * + * **Usage** + * + * ```js + * page.on('console', async msg => { + * const values = []; + * for (const arg of msg.args()) + * values.push(await arg.jsonValue()); + * console.log(...values); + * }); + * await page.evaluate(() => console.log('hello', 5, { foo: 'bar' })); + * ``` + * + */ + addListener(event: 'console', listener: (consoleMessage: ConsoleMessage) => any): this; + + /** + * Emitted when the page crashes. Browser pages might crash if they try to allocate too much memory. When the page + * crashes, ongoing and subsequent operations will throw. + * + * The most common way to deal with crashes is to catch an exception: + * + * ```js + * try { + * // Crash might happen during a click. + * await page.click('button'); + * // Or while waiting for an event. + * await page.waitForEvent('popup'); + * } catch (e) { + * // When the page crashes, exception message contains 'crash'. + * } + * ``` + * + */ + addListener(event: 'crash', listener: (page: Page) => any): this; + + /** + * Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, `confirm` or `beforeunload`. Listener **must** + * either [dialog.accept([promptText])](https://playwright.dev/docs/api/class-dialog#dialog-accept) or + * [dialog.dismiss()](https://playwright.dev/docs/api/class-dialog#dialog-dismiss) the dialog - otherwise the page + * will [freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking) waiting for the + * dialog, and actions like click will never finish. + * + * **Usage** + * + * ```js + * page.on('dialog', dialog => dialog.accept()); + * ``` + * + * **NOTE** When no [page.on('dialog')](https://playwright.dev/docs/api/class-page#page-event-dialog) or + * [browserContext.on('dialog')](https://playwright.dev/docs/api/class-browsercontext#browser-context-event-dialog) + * listeners are present, all dialogs are automatically dismissed. + * + */ + addListener(event: 'dialog', listener: (dialog: Dialog) => any): this; + + /** + * Emitted when the JavaScript + * [`DOMContentLoaded`](https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded) event is dispatched. + */ + addListener(event: 'domcontentloaded', listener: (page: Page) => any): this; + + /** + * Emitted when attachment download started. User can access basic file operations on downloaded content via the + * passed [Download](https://playwright.dev/docs/api/class-download) instance. + */ + addListener(event: 'download', listener: (download: Download) => any): this; + + /** + * Emitted when a file chooser is supposed to appear, such as after clicking the ``. Playwright can + * respond to it via setting the input files using + * [fileChooser.setFiles(files[, options])](https://playwright.dev/docs/api/class-filechooser#file-chooser-set-files) + * that can be uploaded after that. + * + * ```js + * page.on('filechooser', async fileChooser => { + * await fileChooser.setFiles(path.join(__dirname, '/tmp/myfile.pdf')); + * }); + * ``` + * + */ + addListener(event: 'filechooser', listener: (fileChooser: FileChooser) => any): this; + + /** + * Emitted when a frame is attached. + */ + addListener(event: 'frameattached', listener: (frame: Frame) => any): this; + + /** + * Emitted when a frame is detached. + */ + addListener(event: 'framedetached', listener: (frame: Frame) => any): this; + + /** + * Emitted when a frame is navigated to a new url. + */ + addListener(event: 'framenavigated', listener: (frame: Frame) => any): this; + + /** + * Emitted when the JavaScript [`load`](https://developer.mozilla.org/en-US/docs/Web/Events/load) event is dispatched. + */ + addListener(event: 'load', listener: (page: Page) => any): this; + + /** + * Emitted when an uncaught exception happens within the page. + * + * ```js + * // Log all uncaught errors to the terminal + * page.on('pageerror', exception => { + * console.log(`Uncaught exception: "${exception}"`); + * }); + * + * // Navigate to a page with an exception. + * await page.goto('data:text/html,'); + * ``` + * + */ + addListener(event: 'pageerror', listener: (error: Error) => any): this; + + /** + * Emitted when the page opens a new tab or window. This event is emitted in addition to the + * [browserContext.on('page')](https://playwright.dev/docs/api/class-browsercontext#browser-context-event-page), but + * only for popups relevant to this page. + * + * The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a + * popup with `window.open('http://example.com')`, this event will fire when the network request to + * "http://example.com" is done and its response has started loading in the popup. If you would like to route/listen + * to this network request, use + * [browserContext.route(url, handler[, options])](https://playwright.dev/docs/api/class-browsercontext#browser-context-route) + * and + * [browserContext.on('request')](https://playwright.dev/docs/api/class-browsercontext#browser-context-event-request) + * respectively instead of similar methods on the [Page](https://playwright.dev/docs/api/class-page). + * + * ```js + * // Start waiting for popup before clicking. Note no await. + * const popupPromise = page.waitForEvent('popup'); + * await page.getByText('open the popup').click(); + * const popup = await popupPromise; + * console.log(await popup.evaluate('location.href')); + * ``` + * + * **NOTE** Use + * [page.waitForLoadState([state, options])](https://playwright.dev/docs/api/class-page#page-wait-for-load-state) to + * wait until the page gets to a particular state (you should not need it in most cases). + * + */ + addListener(event: 'popup', listener: (page: Page) => any): this; + + /** + * Emitted when a page issues a request. The [request] object is read-only. In order to intercept and mutate requests, + * see [page.route(url, handler[, options])](https://playwright.dev/docs/api/class-page#page-route) or + * [browserContext.route(url, handler[, options])](https://playwright.dev/docs/api/class-browsercontext#browser-context-route). + */ + addListener(event: 'request', listener: (request: Request) => any): this; + + /** + * Emitted when a request fails, for example by timing out. + * + * ```js + * page.on('requestfailed', request => { + * console.log(request.url() + ' ' + request.failure().errorText); + * }); + * ``` + * + * **NOTE** HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request + * will complete with + * [page.on('requestfinished')](https://playwright.dev/docs/api/class-page#page-event-request-finished) event and not + * with [page.on('requestfailed')](https://playwright.dev/docs/api/class-page#page-event-request-failed). A request + * will only be considered failed when the client cannot get an HTTP response from the server, e.g. due to network + * error net::ERR_FAILED. + * + */ + addListener(event: 'requestfailed', listener: (request: Request) => any): this; + + /** + * Emitted when a request finishes successfully after downloading the response body. For a successful response, the + * sequence of events is `request`, `response` and `requestfinished`. + */ + addListener(event: 'requestfinished', listener: (request: Request) => any): this; + + /** + * Emitted when [response] status and headers are received for a request. For a successful response, the sequence of + * events is `request`, `response` and `requestfinished`. + */ + addListener(event: 'response', listener: (response: Response) => any): this; + + /** + * Emitted when [WebSocket](https://playwright.dev/docs/api/class-websocket) request is sent. + */ + addListener(event: 'websocket', listener: (webSocket: WebSocket) => any): this; + + /** + * Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is spawned + * by the page. + */ + addListener(event: 'worker', listener: (worker: Worker) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'close', listener: (page: Page) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'console', listener: (consoleMessage: ConsoleMessage) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'crash', listener: (page: Page) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'dialog', listener: (dialog: Dialog) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'domcontentloaded', listener: (page: Page) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'download', listener: (download: Download) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'filechooser', listener: (fileChooser: FileChooser) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'frameattached', listener: (frame: Frame) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'framedetached', listener: (frame: Frame) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'framenavigated', listener: (frame: Frame) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'load', listener: (page: Page) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'pageerror', listener: (error: Error) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'popup', listener: (page: Page) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'request', listener: (request: Request) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'requestfailed', listener: (request: Request) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'requestfinished', listener: (request: Request) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'response', listener: (response: Response) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'websocket', listener: (webSocket: WebSocket) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + removeListener(event: 'worker', listener: (worker: Worker) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'close', listener: (page: Page) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'console', listener: (consoleMessage: ConsoleMessage) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'crash', listener: (page: Page) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'dialog', listener: (dialog: Dialog) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'domcontentloaded', listener: (page: Page) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'download', listener: (download: Download) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'filechooser', listener: (fileChooser: FileChooser) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'frameattached', listener: (frame: Frame) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'framedetached', listener: (frame: Frame) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'framenavigated', listener: (frame: Frame) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'load', listener: (page: Page) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'pageerror', listener: (error: Error) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'popup', listener: (page: Page) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'request', listener: (request: Request) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'requestfailed', listener: (request: Request) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'requestfinished', listener: (request: Request) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'response', listener: (response: Response) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'websocket', listener: (webSocket: WebSocket) => any): this; + + /** + * Removes an event listener added by `on` or `addListener`. + */ + off(event: 'worker', listener: (worker: Worker) => any): this; + + /** + * Emitted when the page closes. + */ + prependListener(event: 'close', listener: (page: Page) => any): this; + + /** + * Emitted when JavaScript within the page calls one of console API methods, e.g. `console.log` or `console.dir`. + * + * The arguments passed into `console.log` are available on the + * [ConsoleMessage](https://playwright.dev/docs/api/class-consolemessage) event handler argument. + * + * **Usage** + * + * ```js + * page.on('console', async msg => { + * const values = []; + * for (const arg of msg.args()) + * values.push(await arg.jsonValue()); + * console.log(...values); + * }); + * await page.evaluate(() => console.log('hello', 5, { foo: 'bar' })); + * ``` + * + */ + prependListener(event: 'console', listener: (consoleMessage: ConsoleMessage) => any): this; + + /** + * Emitted when the page crashes. Browser pages might crash if they try to allocate too much memory. When the page + * crashes, ongoing and subsequent operations will throw. + * + * The most common way to deal with crashes is to catch an exception: + * + * ```js + * try { + * // Crash might happen during a click. + * await page.click('button'); + * // Or while waiting for an event. + * await page.waitForEvent('popup'); + * } catch (e) { + * // When the page crashes, exception message contains 'crash'. + * } + * ``` + * + */ + prependListener(event: 'crash', listener: (page: Page) => any): this; + + /** + * Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, `confirm` or `beforeunload`. Listener **must** + * either [dialog.accept([promptText])](https://playwright.dev/docs/api/class-dialog#dialog-accept) or + * [dialog.dismiss()](https://playwright.dev/docs/api/class-dialog#dialog-dismiss) the dialog - otherwise the page + * will [freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking) waiting for the + * dialog, and actions like click will never finish. + * + * **Usage** + * + * ```js + * page.on('dialog', dialog => dialog.accept()); + * ``` + * + * **NOTE** When no [page.on('dialog')](https://playwright.dev/docs/api/class-page#page-event-dialog) or + * [browserContext.on('dialog')](https://playwright.dev/docs/api/class-browsercontext#browser-context-event-dialog) + * listeners are present, all dialogs are automatically dismissed. + * + */ + prependListener(event: 'dialog', listener: (dialog: Dialog) => any): this; + + /** + * Emitted when the JavaScript + * [`DOMContentLoaded`](https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded) event is dispatched. + */ + prependListener(event: 'domcontentloaded', listener: (page: Page) => any): this; + + /** + * Emitted when attachment download started. User can access basic file operations on downloaded content via the + * passed [Download](https://playwright.dev/docs/api/class-download) instance. + */ + prependListener(event: 'download', listener: (download: Download) => any): this; + + /** + * Emitted when a file chooser is supposed to appear, such as after clicking the ``. Playwright can + * respond to it via setting the input files using + * [fileChooser.setFiles(files[, options])](https://playwright.dev/docs/api/class-filechooser#file-chooser-set-files) + * that can be uploaded after that. + * + * ```js + * page.on('filechooser', async fileChooser => { + * await fileChooser.setFiles(path.join(__dirname, '/tmp/myfile.pdf')); + * }); + * ``` + * + */ + prependListener(event: 'filechooser', listener: (fileChooser: FileChooser) => any): this; + + /** + * Emitted when a frame is attached. + */ + prependListener(event: 'frameattached', listener: (frame: Frame) => any): this; + + /** + * Emitted when a frame is detached. + */ + prependListener(event: 'framedetached', listener: (frame: Frame) => any): this; + + /** + * Emitted when a frame is navigated to a new url. + */ + prependListener(event: 'framenavigated', listener: (frame: Frame) => any): this; + + /** + * Emitted when the JavaScript [`load`](https://developer.mozilla.org/en-US/docs/Web/Events/load) event is dispatched. + */ + prependListener(event: 'load', listener: (page: Page) => any): this; + + /** + * Emitted when an uncaught exception happens within the page. + * + * ```js + * // Log all uncaught errors to the terminal + * page.on('pageerror', exception => { + * console.log(`Uncaught exception: "${exception}"`); + * }); + * + * // Navigate to a page with an exception. + * await page.goto('data:text/html,'); + * ``` + * + */ + prependListener(event: 'pageerror', listener: (error: Error) => any): this; + + /** + * Emitted when the page opens a new tab or window. This event is emitted in addition to the + * [browserContext.on('page')](https://playwright.dev/docs/api/class-browsercontext#browser-context-event-page), but + * only for popups relevant to this page. + * + * The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a + * popup with `window.open('http://example.com')`, this event will fire when the network request to + * "http://example.com" is done and its response has started loading in the popup. If you would like to route/listen + * to this network request, use + * [browserContext.route(url, handler[, options])](https://playwright.dev/docs/api/class-browsercontext#browser-context-route) + * and + * [browserContext.on('request')](https://playwright.dev/docs/api/class-browsercontext#browser-context-event-request) + * respectively instead of similar methods on the [Page](https://playwright.dev/docs/api/class-page). + * + * ```js + * // Start waiting for popup before clicking. Note no await. + * const popupPromise = page.waitForEvent('popup'); + * await page.getByText('open the popup').click(); + * const popup = await popupPromise; + * console.log(await popup.evaluate('location.href')); + * ``` + * + * **NOTE** Use + * [page.waitForLoadState([state, options])](https://playwright.dev/docs/api/class-page#page-wait-for-load-state) to + * wait until the page gets to a particular state (you should not need it in most cases). + * + */ + prependListener(event: 'popup', listener: (page: Page) => any): this; + + /** + * Emitted when a page issues a request. The [request] object is read-only. In order to intercept and mutate requests, + * see [page.route(url, handler[, options])](https://playwright.dev/docs/api/class-page#page-route) or + * [browserContext.route(url, handler[, options])](https://playwright.dev/docs/api/class-browsercontext#browser-context-route). + */ + prependListener(event: 'request', listener: (request: Request) => any): this; + + /** + * Emitted when a request fails, for example by timing out. + * + * ```js + * page.on('requestfailed', request => { + * console.log(request.url() + ' ' + request.failure().errorText); + * }); + * ``` + * + * **NOTE** HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request + * will complete with + * [page.on('requestfinished')](https://playwright.dev/docs/api/class-page#page-event-request-finished) event and not + * with [page.on('requestfailed')](https://playwright.dev/docs/api/class-page#page-event-request-failed). A request + * will only be considered failed when the client cannot get an HTTP response from the server, e.g. due to network + * error net::ERR_FAILED. + * + */ + prependListener(event: 'requestfailed', listener: (request: Request) => any): this; + + /** + * Emitted when a request finishes successfully after downloading the response body. For a successful response, the + * sequence of events is `request`, `response` and `requestfinished`. + */ + prependListener(event: 'requestfinished', listener: (request: Request) => any): this; + + /** + * Emitted when [response] status and headers are received for a request. For a successful response, the sequence of + * events is `request`, `response` and `requestfinished`. + */ + prependListener(event: 'response', listener: (response: Response) => any): this; + + /** + * Emitted when [WebSocket](https://playwright.dev/docs/api/class-websocket) request is sent. + */ + prependListener(event: 'websocket', listener: (webSocket: WebSocket) => any): this; + + /** + * Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is spawned + * by the page. + */ + prependListener(event: 'worker', listener: (worker: Worker) => any): this; + + /** + * When testing a web page, sometimes unexpected overlays like a "Sign up" dialog appear and block actions you want to + * automate, e.g. clicking a button. These overlays don't always show up in the same way or at the same time, making + * them tricky to handle in automated tests. + * + * This method lets you set up a special function, called a handler, that activates when it detects that overlay is + * visible. The handler's job is to remove the overlay, allowing your test to continue as if the overlay wasn't there. + * + * Things to keep in mind: + * - When an overlay is shown predictably, we recommend explicitly waiting for it in your test and dismissing it as + * a part of your normal test flow, instead of using + * [page.addLocatorHandler(locator, handler[, options])](https://playwright.dev/docs/api/class-page#page-add-locator-handler). + * - Playwright checks for the overlay every time before executing or retrying an action that requires an + * [actionability check](https://playwright.dev/docs/actionability), or before performing an auto-waiting assertion check. When overlay + * is visible, Playwright calls the handler first, and then proceeds with the action/assertion. Note that the + * handler is only called when you perform an action/assertion - if the overlay becomes visible but you don't + * perform any actions, the handler will not be triggered. + * - After executing the handler, Playwright will ensure that overlay that triggered the handler is not visible + * anymore. You can opt-out of this behavior with + * [`noWaitAfter`](https://playwright.dev/docs/api/class-page#page-add-locator-handler-option-no-wait-after). + * - The execution time of the handler counts towards the timeout of the action/assertion that executed the handler. + * If your handler takes too long, it might cause timeouts. + * - You can register multiple handlers. However, only a single handler will be running at a time. Make sure the + * actions within a handler don't depend on another handler. + * + * **NOTE** Running the handler will alter your page state mid-test. For example it will change the currently focused + * element and move the mouse. Make sure that actions that run after the handler are self-contained and do not rely on + * the focus and mouse state being unchanged. + * + * For example, consider a test that calls + * [locator.focus([options])](https://playwright.dev/docs/api/class-locator#locator-focus) followed by + * [keyboard.press(key[, options])](https://playwright.dev/docs/api/class-keyboard#keyboard-press). If your handler + * clicks a button between these two actions, the focused element most likely will be wrong, and key press will happen + * on the unexpected element. Use + * [locator.press(key[, options])](https://playwright.dev/docs/api/class-locator#locator-press) instead to avoid this + * problem. + * + * Another example is a series of mouse actions, where + * [mouse.move(x, y[, options])](https://playwright.dev/docs/api/class-mouse#mouse-move) is followed by + * [mouse.down([options])](https://playwright.dev/docs/api/class-mouse#mouse-down). Again, when the handler runs + * between these two actions, the mouse position will be wrong during the mouse down. Prefer self-contained actions + * like [locator.click([options])](https://playwright.dev/docs/api/class-locator#locator-click) that do not rely on + * the state being unchanged by a handler. + * + * **Usage** + * + * An example that closes a "Sign up to the newsletter" dialog when it appears: + * + * ```js + * // Setup the handler. + * await page.addLocatorHandler(page.getByText('Sign up to the newsletter'), async () => { + * await page.getByRole('button', { name: 'No thanks' }).click(); + * }); + * + * // Write the test as usual. + * await page.goto('https://example.com'); + * await page.getByRole('button', { name: 'Start here' }).click(); + * ``` + * + * An example that skips the "Confirm your security details" page when it is shown: + * + * ```js + * // Setup the handler. + * await page.addLocatorHandler(page.getByText('Confirm your security details'), async () => { + * await page.getByRole('button', { name: 'Remind me later' }).click(); + * }); + * + * // Write the test as usual. + * await page.goto('https://example.com'); + * await page.getByRole('button', { name: 'Start here' }).click(); + * ``` + * + * An example with a custom callback on every actionability check. It uses a `` locator that is always visible, + * so the handler is called before every actionability check. It is important to specify + * [`noWaitAfter`](https://playwright.dev/docs/api/class-page#page-add-locator-handler-option-no-wait-after), because + * the handler does not hide the `` element. + * + * ```js + * // Setup the handler. + * await page.addLocatorHandler(page.locator('body'), async () => { + * await page.evaluate(() => window.removeObstructionsForTestIfNeeded()); + * }, { noWaitAfter: true }); + * + * // Write the test as usual. + * await page.goto('https://example.com'); + * await page.getByRole('button', { name: 'Start here' }).click(); + * ``` + * + * Handler takes the original locator as an argument. You can also automatically remove the handler after a number of + * invocations by setting [`times`](https://playwright.dev/docs/api/class-page#page-add-locator-handler-option-times): + * + * ```js + * await page.addLocatorHandler(page.getByLabel('Close'), async locator => { + * await locator.click(); + * }, { times: 1 }); + * ``` + * + * @param locator Locator that triggers the handler. + * @param handler Function that should be run once + * [`locator`](https://playwright.dev/docs/api/class-page#page-add-locator-handler-option-locator) appears. This + * function should get rid of the element that blocks actions like click. + * @param options + */ + addLocatorHandler(locator: Locator, handler: ((locator: Locator) => Promise), options?: { + /** + * By default, after calling the handler Playwright will wait until the overlay becomes hidden, and only then + * Playwright will continue with the action/assertion that triggered the handler. This option allows to opt-out of + * this behavior, so that overlay can stay visible after the handler has run. + */ + noWaitAfter?: boolean; + + /** + * Specifies the maximum number of times this handler should be called. Unlimited by default. + */ + times?: number; + }): Promise; + + /** + * Adds a ` + * + *
+ * `); + * await page.click('button'); + * })(); + * ``` + * + * @param name Name of the function on the window object + * @param callback Callback function which will be called in Playwright's context. + */ + exposeFunction(name: string, callback: Function): Promise; + + /** + * **NOTE** Use locator-based [locator.fill(value[, options])](https://playwright.dev/docs/api/class-locator#locator-fill) + * instead. Read more about [locators](https://playwright.dev/docs/locators). + * + * This method waits for an element matching + * [`selector`](https://playwright.dev/docs/api/class-page#page-fill-option-selector), waits for + * [actionability](https://playwright.dev/docs/actionability) checks, focuses the element, fills it and triggers an `input` event after + * filling. Note that you can pass an empty string to clear the input field. + * + * If the target element is not an ``, ` should not report AAA as a child of the textarea. + if (ariaNode.role !== 'textbox' && text) ariaNode.children.push(node.nodeValue || ''); return; } diff --git a/packages/playwright-core/src/server/injected/consoleApi.ts b/packages/playwright-core/src/server/injected/consoleApi.ts index eae874834ec10..5bcd94a5bfa11 100644 --- a/packages/playwright-core/src/server/injected/consoleApi.ts +++ b/packages/playwright-core/src/server/injected/consoleApi.ts @@ -14,12 +14,13 @@ * limitations under the License. */ -import type { ByRoleOptions } from '../../utils/isomorphic/locatorUtils'; +import { asLocator } from '../../utils/isomorphic/locatorGenerators'; import { getByAltTextSelector, getByLabelSelector, getByPlaceholderSelector, getByRoleSelector, getByTestIdSelector, getByTextSelector, getByTitleSelector } from '../../utils/isomorphic/locatorUtils'; import { escapeForTextSelector } from '../../utils/isomorphic/stringUtils'; -import { asLocator } from '../../utils/isomorphic/locatorGenerators'; -import type { Language } from '../../utils/isomorphic/locatorGenerators'; + import type { InjectedScript } from './injectedScript'; +import type { Language } from '../../utils/isomorphic/locatorGenerators'; +import type { ByRoleOptions } from '../../utils/isomorphic/locatorUtils'; const selectorSymbol = Symbol('selector'); @@ -28,7 +29,7 @@ class Locator { element: Element | undefined; elements: Element[] | undefined; - constructor(injectedScript: InjectedScript, selector: string, options?: { hasText?: string | RegExp, hasNotText?: string | RegExp, has?: Locator, hasNot?: Locator }) { + constructor(injectedScript: InjectedScript, selector: string, options?: { hasText?: string | RegExp, hasNotText?: string | RegExp, has?: Locator, hasNot?: Locator, visible?: boolean }) { if (options?.hasText) selector += ` >> internal:has-text=${escapeForTextSelector(options.hasText, false)}`; if (options?.hasNotText) @@ -37,6 +38,8 @@ class Locator { selector += ` >> internal:has=` + JSON.stringify(options.has[selectorSymbol]); if (options?.hasNot) selector += ` >> internal:has-not=` + JSON.stringify(options.hasNot[selectorSymbol]); + if (options?.visible !== undefined) + selector += ` >> visible=${options.visible ? 'true' : 'false'}`; this[selectorSymbol] = selector; if (selector) { const parsed = injectedScript.parseSelector(selector); @@ -45,7 +48,7 @@ class Locator { } const selectorBase = selector; const self = this as any; - self.locator = (selector: string, options?: { hasText?: string | RegExp, has?: Locator }): Locator => { + self.locator = (selector: string, options?: { hasText?: string | RegExp, hasNotText?: string | RegExp, has?: Locator, hasNot?: Locator }): Locator => { return new Locator(injectedScript, selectorBase ? selectorBase + ' >> ' + selector : selector, options); }; self.getByTestId = (testId: string): Locator => self.locator(getByTestIdSelector(injectedScript.testIdAttributeNameForStrictErrorAndConsoleCodegen(), testId)); @@ -55,7 +58,7 @@ class Locator { self.getByText = (text: string | RegExp, options?: { exact?: boolean }): Locator => self.locator(getByTextSelector(text, options)); self.getByTitle = (text: string | RegExp, options?: { exact?: boolean }): Locator => self.locator(getByTitleSelector(text, options)); self.getByRole = (role: string, options: ByRoleOptions = {}): Locator => self.locator(getByRoleSelector(role, options)); - self.filter = (options?: { hasText?: string | RegExp, has?: Locator }): Locator => new Locator(injectedScript, selector, options); + self.filter = (options?: { hasText?: string | RegExp, hasNotText?: string | RegExp, has?: Locator, hasNot?: Locator, visible?: boolean }): Locator => new Locator(injectedScript, selector, options); self.first = (): Locator => self.locator('nth=0'); self.last = (): Locator => self.locator('nth=-1'); self.nth = (index: number): Locator => self.locator(`nth=${index}`); @@ -85,10 +88,8 @@ class ConsoleAPI { inspect: (selector: string) => this._inspect(selector), selector: (element: Element) => this._selector(element), generateLocator: (element: Element, language?: Language) => this._generateLocator(element, language), - ariaSnapshot: (element?: Element) => { - const snapshot = this._injectedScript.ariaSnapshot(element || this._injectedScript.document.body); - // eslint-disable-next-line no-console - console.log(snapshot); + ariaSnapshot: (element?: Element, options?: { id?: boolean }) => { + return this._injectedScript.ariaSnapshot(element || this._injectedScript.document.body, options); }, resume: () => this._resume(), ...new Locator(injectedScript, ''), diff --git a/packages/playwright-core/src/server/injected/highlight.ts b/packages/playwright-core/src/server/injected/highlight.ts index 5720ffc5393dc..332a6a77549ce 100644 --- a/packages/playwright-core/src/server/injected/highlight.ts +++ b/packages/playwright-core/src/server/injected/highlight.ts @@ -14,12 +14,14 @@ * limitations under the License. */ +import highlightCSS from './highlight.css?inline'; +import { asLocator } from '../../utils/isomorphic/locatorGenerators'; import { stringifySelector } from '../../utils/isomorphic/selectorParser'; -import type { ParsedSelector } from '../../utils/isomorphic/selectorParser'; + import type { InjectedScript } from './injectedScript'; -import { asLocator } from '../../utils/isomorphic/locatorGenerators'; import type { Language } from '../../utils/isomorphic/locatorGenerators'; -import highlightCSS from './highlight.css?inline'; +import type { ParsedSelector } from '../../utils/isomorphic/selectorParser'; + type HighlightEntry = { targetElement: Element, diff --git a/packages/playwright-core/src/server/injected/injectedScript.ts b/packages/playwright-core/src/server/injected/injectedScript.ts index 17380db1702a2..70374852f7ffc 100644 --- a/packages/playwright-core/src/server/injected/injectedScript.ts +++ b/packages/playwright-core/src/server/injected/injectedScript.ts @@ -14,30 +14,36 @@ * limitations under the License. */ -import type { SelectorEngine, SelectorRoot } from './selectorEngine'; -import { XPathEngine } from './xpathSelectorEngine'; +import { parseAriaSnapshot } from '@isomorphic/ariaSnapshot'; + +import { generateAriaTree, getAllByAria, matchesAriaTree, renderAriaTree } from './ariaSnapshot'; +import { enclosingShadowRootOrDocument, isElementVisible, isInsideScope, parentElementOrShadowHost, setBrowserName } from './domUtils'; +import { Highlight } from './highlight'; +import { kLayoutSelectorNames, layoutSelectorScore } from './layoutSelectorUtils'; import { ReactEngine } from './reactSelectorEngine'; -import { VueEngine } from './vueSelectorEngine'; import { createRoleEngine } from './roleSelectorEngine'; -import { parseAttributeSelector } from '../../utils/isomorphic/selectorParser'; -import type { NestedSelectorBody, ParsedSelector, ParsedSelectorPart } from '../../utils/isomorphic/selectorParser'; -import { visitAllSelectorParts, parseSelector, stringifySelector } from '../../utils/isomorphic/selectorParser'; -import { type TextMatcher, elementMatchesText, elementText, type ElementText, getElementLabels } from './selectorUtils'; +import { getAriaDisabled, getAriaRole, getCheckedAllowMixed, getCheckedWithoutMixed, getElementAccessibleDescription, getElementAccessibleErrorMessage, getElementAccessibleName, getReadonly } from './roleUtils'; import { SelectorEvaluatorImpl, sortInDOMOrder } from './selectorEvaluator'; -import { enclosingShadowRootOrDocument, isElementVisible, isInsideScope, parentElementOrShadowHost, setBrowserName } from './domUtils'; -import type { CSSComplexSelectorList } from '../../utils/isomorphic/cssParser'; -import { generateSelector, type GenerateSelectorOptions } from './selectorGenerator'; -import type * as channels from '@protocol/channels'; -import { Highlight } from './highlight'; -import { getAriaDisabled, getAriaRole, getElementAccessibleName, getElementAccessibleDescription, getReadonly, getElementAccessibleErrorMessage, getCheckedAllowMixed, getCheckedWithoutMixed } from './roleUtils'; -import { kLayoutSelectorNames, type LayoutSelectorName, layoutSelectorScore } from './layoutSelectorUtils'; +import { generateSelector } from './selectorGenerator'; +import { elementMatchesText, elementText, getElementLabels } from './selectorUtils'; +import { VueEngine } from './vueSelectorEngine'; +import { XPathEngine } from './xpathSelectorEngine'; import { asLocator } from '../../utils/isomorphic/locatorGenerators'; -import type { Language } from '../../utils/isomorphic/locatorGenerators'; +import { parseAttributeSelector } from '../../utils/isomorphic/selectorParser'; +import { parseSelector, stringifySelector, visitAllSelectorParts } from '../../utils/isomorphic/selectorParser'; import { cacheNormalizedWhitespaces, normalizeWhiteSpace, trimStringWithEllipsis } from '../../utils/isomorphic/stringUtils'; -import { matchesAriaTree, getAllByAria, generateAriaTree, renderAriaTree } from './ariaSnapshot'; + import type { AriaNode, AriaSnapshot } from './ariaSnapshot'; +import type { LayoutSelectorName } from './layoutSelectorUtils'; +import type { SelectorEngine, SelectorRoot } from './selectorEngine'; +import type { GenerateSelectorOptions } from './selectorGenerator'; +import type { ElementText, TextMatcher } from './selectorUtils'; +import type { CSSComplexSelectorList } from '../../utils/isomorphic/cssParser'; +import type { Language } from '../../utils/isomorphic/locatorGenerators'; +import type { NestedSelectorBody, ParsedSelector, ParsedSelectorPart } from '../../utils/isomorphic/selectorParser'; import type { AriaTemplateNode } from '@isomorphic/ariaSnapshot'; -import { parseAriaSnapshot } from '@isomorphic/ariaSnapshot'; +import type * as channels from '@protocol/channels'; + export type FrameExpectParams = Omit & { expectedValue?: any }; @@ -72,6 +78,7 @@ export class InjectedScript { // eslint-disable-next-line no-restricted-globals readonly window: Window & typeof globalThis; readonly document: Document; + private _ariaElementById: Map | undefined; // Recorder must use any external dependencies through InjectedScript. // Otherwise it will end up with a copy of all modules it uses, and any @@ -130,6 +137,7 @@ export class InjectedScript { this._engines.set('internal:attr', this._createNamedAttributeEngine()); this._engines.set('internal:testid', this._createNamedAttributeEngine()); this._engines.set('internal:role', createRoleEngine(true)); + this._engines.set('internal:aria-id', this._createAriaIdEngine()); for (const { name, engine } of customEngines) this._engines.set(name, engine); @@ -221,7 +229,8 @@ export class InjectedScript { if (node.nodeType !== Node.ELEMENT_NODE) throw this.createStacklessError('Can only capture aria snapshot of Element nodes.'); const ariaSnapshot = generateAriaTree(node as Element); - return renderAriaTree(ariaSnapshot.root, options); + this._ariaElementById = ariaSnapshot.elements; + return renderAriaTree(ariaSnapshot.root, { ...options, ids: options?.id ? ariaSnapshot.ids : undefined }); } ariaSnapshotAsObject(node: Node): AriaSnapshot { @@ -609,6 +618,15 @@ export class InjectedScript { return result; } + _createAriaIdEngine() { + const queryAll = (root: SelectorRoot, selector: string): Element[] => { + const ariaId = parseInt(selector, 10); + const result = this._ariaElementById?.get(ariaId); + return result && result.isConnected ? [result] : []; + }; + return { queryAll }; + } + elementState(node: Node, state: ElementStateWithoutStable): ElementStateQueryResult { const element = this.retarget(node, ['visible', 'hidden'].includes(state) ? 'none' : 'follow-label'); if (!element || !element.isConnected) { diff --git a/packages/playwright-core/src/server/injected/reactSelectorEngine.ts b/packages/playwright-core/src/server/injected/reactSelectorEngine.ts index 2d0e51f0b2799..5beb3cc9ee790 100644 --- a/packages/playwright-core/src/server/injected/reactSelectorEngine.ts +++ b/packages/playwright-core/src/server/injected/reactSelectorEngine.ts @@ -14,11 +14,12 @@ * limitations under the License. */ -import type { SelectorEngine, SelectorRoot } from './selectorEngine'; import { isInsideScope } from './domUtils'; import { matchesComponentAttribute } from './selectorUtils'; import { parseAttributeSelector } from '../../utils/isomorphic/selectorParser'; +import type { SelectorEngine, SelectorRoot } from './selectorEngine'; + type ComponentNode = { key?: any, name: string, diff --git a/packages/playwright-core/src/server/injected/recorder/pollingRecorder.ts b/packages/playwright-core/src/server/injected/recorder/pollingRecorder.ts index bc96ff2185f36..fd9a3edf98a79 100644 --- a/packages/playwright-core/src/server/injected/recorder/pollingRecorder.ts +++ b/packages/playwright-core/src/server/injected/recorder/pollingRecorder.ts @@ -14,11 +14,12 @@ * limitations under the License. */ -import type { ElementInfo, Mode, OverlayState, UIState } from '@recorder/recorderTypes'; -import type * as actions from '@recorder/actions'; -import type { InjectedScript } from '../injectedScript'; import { Recorder } from './recorder'; + +import type { InjectedScript } from '../injectedScript'; import type { RecorderDelegate } from './recorder'; +import type * as actions from '@recorder/actions'; +import type { ElementInfo, Mode, OverlayState, UIState } from '@recorder/recorderTypes'; interface Embedder { __pw_recorderPerformAction(action: actions.PerformOnRecordAction): Promise; @@ -34,6 +35,7 @@ export class PollingRecorder implements RecorderDelegate { private _recorder: Recorder; private _embedder: Embedder; private _pollRecorderModeTimer: number | undefined; + private _lastStateJSON: string | undefined; constructor(injectedScript: InjectedScript) { this._recorder = new Recorder(injectedScript); @@ -42,6 +44,7 @@ export class PollingRecorder implements RecorderDelegate { injectedScript.onGlobalListenersRemoved.add(() => this._recorder.installListeners()); const refreshOverlay = () => { + this._lastStateJSON = undefined; this._pollRecorderMode().catch(e => console.log(e)); // eslint-disable-line no-console }; this._embedder.__pw_refreshOverlay = refreshOverlay; @@ -57,13 +60,19 @@ export class PollingRecorder implements RecorderDelegate { this._pollRecorderModeTimer = this._recorder.injectedScript.builtinSetTimeout(() => this._pollRecorderMode(), pollPeriod); return; } - const win = this._recorder.document.defaultView!; - if (win.top !== win) { - // Only show action point in the main frame, since it is relative to the page's viewport. - // Otherwise we'll see multiple action points at different locations. - state.actionPoint = undefined; + + const stringifiedState = JSON.stringify(state); + if (this._lastStateJSON !== stringifiedState) { + this._lastStateJSON = stringifiedState; + const win = this._recorder.document.defaultView!; + if (win.top !== win) { + // Only show action point in the main frame, since it is relative to the page's viewport. + // Otherwise we'll see multiple action points at different locations. + state.actionPoint = undefined; + } + this._recorder.setUIState(state, this); } - this._recorder.setUIState(state, this); + this._pollRecorderModeTimer = this._recorder.injectedScript.builtinSetTimeout(() => this._pollRecorderMode(), pollPeriod); } diff --git a/packages/playwright-core/src/server/injected/recorder/recorder.ts b/packages/playwright-core/src/server/injected/recorder/recorder.ts index 3df43f751ec2f..68fa96e77f8c4 100644 --- a/packages/playwright-core/src/server/injected/recorder/recorder.ts +++ b/packages/playwright-core/src/server/injected/recorder/recorder.ts @@ -14,13 +14,14 @@ * limitations under the License. */ -import type * as actions from '@recorder/actions'; +import clipPaths from './clipPaths'; + +import type { Point } from '../../../utils/isomorphic/types'; +import type { Highlight, HighlightOptions } from '../highlight'; import type { InjectedScript } from '../injectedScript'; -import type { Point } from '../../../common/types'; -import type { ElementInfo, Mode, OverlayState, UIState } from '@recorder/recorderTypes'; import type { ElementText } from '../selectorUtils'; -import type { Highlight, HighlightOptions } from '../highlight'; -import clipPaths from './clipPaths'; +import type * as actions from '@recorder/actions'; +import type { ElementInfo, Mode, OverlayState, UIState } from '@recorder/recorderTypes'; export interface RecorderDelegate { performAction?(action: actions.PerformOnRecordAction): Promise; diff --git a/packages/playwright-core/src/server/injected/roleSelectorEngine.ts b/packages/playwright-core/src/server/injected/roleSelectorEngine.ts index b647f81b8eb45..2a9c8f648e42d 100644 --- a/packages/playwright-core/src/server/injected/roleSelectorEngine.ts +++ b/packages/playwright-core/src/server/injected/roleSelectorEngine.ts @@ -14,12 +14,14 @@ * limitations under the License. */ -import type { SelectorEngine, SelectorRoot } from './selectorEngine'; -import { matchesAttributePart } from './selectorUtils'; import { beginAriaCaches, endAriaCaches, getAriaChecked, getAriaDisabled, getAriaExpanded, getAriaLevel, getAriaPressed, getAriaRole, getAriaSelected, getElementAccessibleName, isElementHiddenForAria, kAriaCheckedRoles, kAriaExpandedRoles, kAriaLevelRoles, kAriaPressedRoles, kAriaSelectedRoles } from './roleUtils'; -import { parseAttributeSelector, type AttributeSelectorPart, type AttributeSelectorOperator } from '../../utils/isomorphic/selectorParser'; +import { matchesAttributePart } from './selectorUtils'; +import { parseAttributeSelector } from '../../utils/isomorphic/selectorParser'; import { normalizeWhiteSpace } from '../../utils/isomorphic/stringUtils'; +import type { SelectorEngine, SelectorRoot } from './selectorEngine'; +import type { AttributeSelectorOperator, AttributeSelectorPart } from '../../utils/isomorphic/selectorParser'; + type RoleEngineOptions = { role: string; name?: string | RegExp; diff --git a/packages/playwright-core/src/server/injected/roleUtils.ts b/packages/playwright-core/src/server/injected/roleUtils.ts index 5ed6fd7b85bd8..5b4e25940d195 100644 --- a/packages/playwright-core/src/server/injected/roleUtils.ts +++ b/packages/playwright-core/src/server/injected/roleUtils.ts @@ -14,9 +14,10 @@ * limitations under the License. */ -import type { AriaRole } from '@isomorphic/ariaSnapshot'; import { closestCrossShadow, elementSafeTagName, enclosingShadowRootOrDocument, getElementComputedStyle, isElementStyleVisibilityVisible, isVisibleTextNode, parentElementOrShadowHost } from './domUtils'; +import type { AriaRole } from '@isomorphic/ariaSnapshot'; + function hasExplicitAccessibleName(e: Element) { return e.hasAttribute('aria-label') || e.hasAttribute('aria-labelledby'); } @@ -336,7 +337,7 @@ function trimFlatString(s: string): string { function asFlatString(s: string): string { // "Flat string" at https://w3c.github.io/accname/#terminology // Note that non-breaking spaces are preserved. - return s.split('\u00A0').map(chunk => chunk.replace(/\r\n/g, '\n').replace(/\s\s*/g, ' ')).join('\u00A0').trim(); + return s.split('\u00A0').map(chunk => chunk.replace(/\r\n/g, '\n').replace(/[\u200b\u00ad]/g, '').replace(/\s\s*/g, ' ')).join('\u00A0').trim(); } function queryInAriaOwned(element: Element, selector: string): Element[] { @@ -354,27 +355,34 @@ export function getPseudoContent(element: Element, pseudo: '::before' | '::after if (cache?.has(element)) return cache?.get(element) || ''; const pseudoStyle = getElementComputedStyle(element, pseudo); - const content = getPseudoContentImpl(pseudoStyle); + const content = getPseudoContentImpl(element, pseudoStyle); if (cache) cache.set(element, content); return content; } -function getPseudoContentImpl(pseudoStyle: CSSStyleDeclaration | undefined) { +function getPseudoContentImpl(element: Element, pseudoStyle: CSSStyleDeclaration | undefined) { // Note: all browsers ignore display:none and visibility:hidden pseudos. if (!pseudoStyle || pseudoStyle.display === 'none' || pseudoStyle.visibility === 'hidden') return ''; const content = pseudoStyle.content; + let resolvedContent: string | undefined; if ((content[0] === '\'' && content[content.length - 1] === '\'') || (content[0] === '"' && content[content.length - 1] === '"')) { - const unquoted = content.substring(1, content.length - 1); + resolvedContent = content.substring(1, content.length - 1); + } else if (content.startsWith('attr(') && content.endsWith(')')) { + // Firefox does not resolve attribute accessors in content. + const attrName = content.substring('attr('.length, content.length - 1).trim(); + resolvedContent = element.getAttribute(attrName) || ''; + } + if (resolvedContent !== undefined) { // SPEC DIFFERENCE. // Spec says "CSS textual content, without a space", but we account for display // to pass "name_file-label-inline-block-styles-manual.html" const display = pseudoStyle.display || 'inline'; if (display !== 'inline') - return ' ' + unquoted + ' '; - return unquoted; + return ' ' + resolvedContent + ' '; + return resolvedContent; } return ''; } diff --git a/packages/playwright-core/src/server/injected/selectorEvaluator.ts b/packages/playwright-core/src/server/injected/selectorEvaluator.ts index d2f481526fd95..7d55229166b2a 100644 --- a/packages/playwright-core/src/server/injected/selectorEvaluator.ts +++ b/packages/playwright-core/src/server/injected/selectorEvaluator.ts @@ -14,13 +14,16 @@ * limitations under the License. */ -import type { CSSComplexSelector, CSSSimpleSelector, CSSComplexSelectorList, CSSFunctionArgument } from '../../utils/isomorphic/cssParser'; -import { customCSSNames } from '../../utils/isomorphic/selectorParser'; import { isElementVisible, parentElementOrShadowHost } from './domUtils'; -import { type LayoutSelectorName, layoutSelectorScore } from './layoutSelectorUtils'; -import { elementMatchesText, elementText, shouldSkipForTextMatching, type ElementText } from './selectorUtils'; +import { layoutSelectorScore } from './layoutSelectorUtils'; +import { elementMatchesText, elementText, shouldSkipForTextMatching } from './selectorUtils'; +import { customCSSNames } from '../../utils/isomorphic/selectorParser'; import { normalizeWhiteSpace } from '../../utils/isomorphic/stringUtils'; +import type { LayoutSelectorName } from './layoutSelectorUtils'; +import type { ElementText } from './selectorUtils'; +import type { CSSComplexSelector, CSSComplexSelectorList, CSSFunctionArgument, CSSSimpleSelector } from '../../utils/isomorphic/cssParser'; + type QueryContext = { scope: Element | Document; pierceShadow: boolean; diff --git a/packages/playwright-core/src/server/injected/selectorGenerator.ts b/packages/playwright-core/src/server/injected/selectorGenerator.ts index 04f15987621fe..70541abfc043a 100644 --- a/packages/playwright-core/src/server/injected/selectorGenerator.ts +++ b/packages/playwright-core/src/server/injected/selectorGenerator.ts @@ -14,11 +14,12 @@ * limitations under the License. */ -import { cssEscape, escapeForAttributeSelector, escapeForTextSelector, escapeRegExp, quoteCSSAttributeValue } from '../../utils/isomorphic/stringUtils'; import { closestCrossShadow, isElementVisible, isInsideScope, parentElementOrShadowHost } from './domUtils'; -import type { InjectedScript } from './injectedScript'; -import { getAriaRole, getElementAccessibleName, beginAriaCaches, endAriaCaches } from './roleUtils'; +import { beginAriaCaches, endAriaCaches, getAriaRole, getElementAccessibleName } from './roleUtils'; import { elementText, getElementLabels } from './selectorUtils'; +import { cssEscape, escapeForAttributeSelector, escapeForTextSelector, escapeRegExp, quoteCSSAttributeValue } from '../../utils/isomorphic/stringUtils'; + +import type { InjectedScript } from './injectedScript'; type SelectorToken = { engine: string; diff --git a/packages/playwright-core/src/server/injected/selectorUtils.ts b/packages/playwright-core/src/server/injected/selectorUtils.ts index da0f869fa0f64..31db84683dc0f 100644 --- a/packages/playwright-core/src/server/injected/selectorUtils.ts +++ b/packages/playwright-core/src/server/injected/selectorUtils.ts @@ -14,9 +14,10 @@ * limitations under the License. */ -import type { AttributeSelectorPart } from '../../utils/isomorphic/selectorParser'; -import { normalizeWhiteSpace } from '../../utils/isomorphic/stringUtils'; import { getAriaLabelledByElements } from './roleUtils'; +import { normalizeWhiteSpace } from '../../utils/isomorphic/stringUtils'; + +import type { AttributeSelectorPart } from '../../utils/isomorphic/selectorParser'; export function matchesComponentAttribute(obj: any, attr: AttributeSelectorPart) { for (const token of attr.jsonPath) { diff --git a/packages/playwright-core/src/server/injected/utilityScript.ts b/packages/playwright-core/src/server/injected/utilityScript.ts index 7b046a529af8f..2a987802ff5bc 100644 --- a/packages/playwright-core/src/server/injected/utilityScript.ts +++ b/packages/playwright-core/src/server/injected/utilityScript.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { serializeAsCallArgument, parseEvaluationResultValue } from '../isomorphic/utilityScriptSerializers'; +import { parseEvaluationResultValue, serializeAsCallArgument } from '../isomorphic/utilityScriptSerializers'; export class UtilityScript { constructor(isUnderTest: boolean) { diff --git a/packages/playwright-core/src/server/injected/vueSelectorEngine.ts b/packages/playwright-core/src/server/injected/vueSelectorEngine.ts index 154f36b983071..a9f179bf435d6 100644 --- a/packages/playwright-core/src/server/injected/vueSelectorEngine.ts +++ b/packages/playwright-core/src/server/injected/vueSelectorEngine.ts @@ -14,11 +14,12 @@ * limitations under the License. */ -import type { SelectorEngine, SelectorRoot } from './selectorEngine'; import { isInsideScope } from './domUtils'; import { matchesComponentAttribute } from './selectorUtils'; import { parseAttributeSelector } from '../../utils/isomorphic/selectorParser'; +import type { SelectorEngine, SelectorRoot } from './selectorEngine'; + type ComponentNode = { name: string, children: ComponentNode[], diff --git a/packages/playwright-core/src/server/input.ts b/packages/playwright-core/src/server/input.ts index f8beb789f804d..62261edfae040 100644 --- a/packages/playwright-core/src/server/input.ts +++ b/packages/playwright-core/src/server/input.ts @@ -16,9 +16,10 @@ import { assert } from '../utils'; import * as keyboardLayout from './usKeyboardLayout'; -import type * as types from './types'; -import type { Page } from './page'; + import type { CallMetadata } from './instrumentation'; +import type { Page } from './page'; +import type * as types from './types'; export const keypadLocation = keyboardLayout.keypadLocation; diff --git a/packages/playwright-core/src/server/instrumentation.ts b/packages/playwright-core/src/server/instrumentation.ts index 2a384fb16978c..076008a31e374 100644 --- a/packages/playwright-core/src/server/instrumentation.ts +++ b/packages/playwright-core/src/server/instrumentation.ts @@ -15,14 +15,20 @@ */ import { EventEmitter } from 'events'; -import { createGuid } from '../utils'; -import type { APIRequestContext } from './fetch'; + +import { createGuid } from './utils/crypto'; + import type { Browser } from './browser'; import type { BrowserContext } from './browserContext'; import type { BrowserType } from './browserType'; +import type { Dialog } from './dialog'; +import type { Download } from './download'; +import type { APIRequestContext } from './fetch'; import type { Frame } from './frames'; import type { Page } from './page'; import type { Playwright } from './playwright'; +import type { CallMetadata } from '@protocol/callMetadata'; +export type { CallMetadata } from '@protocol/callMetadata'; export type Attribution = { playwright: Playwright; @@ -33,11 +39,6 @@ export type Attribution = { frame?: Frame; }; -import type { CallMetadata } from '@protocol/callMetadata'; -import type { Dialog } from './dialog'; -import type { Download } from './download'; -export type { CallMetadata } from '@protocol/callMetadata'; - export class SdkObject extends EventEmitter { guid: string; attribution: Attribution; diff --git a/packages/playwright-core/src/server/isomorphic/utilityScriptSerializers.ts b/packages/playwright-core/src/server/isomorphic/utilityScriptSerializers.ts index 6df7988caf7f9..08a167240f0ae 100644 --- a/packages/playwright-core/src/server/isomorphic/utilityScriptSerializers.ts +++ b/packages/playwright-core/src/server/isomorphic/utilityScriptSerializers.ts @@ -129,10 +129,13 @@ export function source() { function serialize(value: any, handleSerializer: (value: any) => HandleOrValue, visitorInfo: VisitorInfo): SerializedValue { if (value && typeof value === 'object') { + // eslint-disable-next-line no-restricted-globals if (typeof globalThis.Window === 'function' && value instanceof globalThis.Window) return 'ref: '; + // eslint-disable-next-line no-restricted-globals if (typeof globalThis.Document === 'function' && value instanceof globalThis.Document) return 'ref: '; + // eslint-disable-next-line no-restricted-globals if (typeof globalThis.Node === 'function' && value instanceof globalThis.Node) return 'ref: '; } diff --git a/packages/playwright-core/src/server/javascript.ts b/packages/playwright-core/src/server/javascript.ts index dbbe89d5c202f..f01cb88bcfa7d 100644 --- a/packages/playwright-core/src/server/javascript.ts +++ b/packages/playwright-core/src/server/javascript.ts @@ -14,19 +14,14 @@ * limitations under the License. */ -import type * as dom from './dom'; -import * as utilityScriptSource from '../generated/utilityScriptSource'; -import { serializeAsCallArgument } from './isomorphic/utilityScriptSerializers'; -import type { UtilityScript } from './injected/utilityScript'; import { SdkObject } from './instrumentation'; -import { LongStandingScope } from '../utils/manualPromise'; +import * as utilityScriptSource from '../generated/utilityScriptSource'; import { isUnderTest } from '../utils'; +import { serializeAsCallArgument } from './isomorphic/utilityScriptSerializers'; +import { LongStandingScope } from '../utils/isomorphic/manualPromise'; -export type ObjectId = string; -export type RemoteObject = { - objectId?: ObjectId, - value?: any -}; +import type * as dom from './dom'; +import type { UtilityScript } from './injected/utilityScript'; interface TaggedAsJSHandle { __jshandle: T; @@ -52,15 +47,14 @@ export type SmartHandle = T extends Node ? dom.ElementHandle : JSHandle export interface ExecutionContextDelegate { rawEvaluateJSON(expression: string): Promise; - rawEvaluateHandle(expression: string): Promise; - evaluateWithArguments(expression: string, returnByValue: boolean, utilityScript: JSHandle, values: any[], objectIds: ObjectId[]): Promise; - getProperties(context: ExecutionContext, objectId: ObjectId): Promise>; - createHandle(context: ExecutionContext, remoteObject: RemoteObject): JSHandle; - releaseHandle(objectId: ObjectId): Promise; + rawEvaluateHandle(context: ExecutionContext, expression: string): Promise; + evaluateWithArguments(expression: string, returnByValue: boolean, utilityScript: JSHandle, values: any[], handles: JSHandle[]): Promise; + getProperties(object: JSHandle): Promise>; + releaseHandle(handle: JSHandle): Promise; } export class ExecutionContext extends SdkObject { - private _delegate: ExecutionContextDelegate; + readonly delegate: ExecutionContextDelegate; private _utilityScriptPromise: Promise | undefined; private _contextDestroyedScope = new LongStandingScope(); readonly worldNameForTest: string; @@ -68,7 +62,7 @@ export class ExecutionContext extends SdkObject { constructor(parent: SdkObject, delegate: ExecutionContextDelegate, worldNameForTest: string) { super(parent, 'execution-context'); this.worldNameForTest = worldNameForTest; - this._delegate = delegate; + this.delegate = delegate; } contextDestroyed(reason: string) { @@ -80,34 +74,31 @@ export class ExecutionContext extends SdkObject { } rawEvaluateJSON(expression: string): Promise { - return this._raceAgainstContextDestroyed(this._delegate.rawEvaluateJSON(expression)); - } - - rawEvaluateHandle(expression: string): Promise { - return this._raceAgainstContextDestroyed(this._delegate.rawEvaluateHandle(expression)); + return this._raceAgainstContextDestroyed(this.delegate.rawEvaluateJSON(expression)); } - evaluateWithArguments(expression: string, returnByValue: boolean, utilityScript: JSHandle, values: any[], objectIds: ObjectId[]): Promise { - return this._raceAgainstContextDestroyed(this._delegate.evaluateWithArguments(expression, returnByValue, utilityScript, values, objectIds)); + rawEvaluateHandle(expression: string): Promise { + return this._raceAgainstContextDestroyed(this.delegate.rawEvaluateHandle(this, expression)); } - getProperties(context: ExecutionContext, objectId: ObjectId): Promise> { - return this._raceAgainstContextDestroyed(this._delegate.getProperties(context, objectId)); + async evaluateWithArguments(expression: string, returnByValue: boolean, values: any[], handles: JSHandle[]): Promise { + const utilityScript = await this._utilityScript(); + return this._raceAgainstContextDestroyed(this.delegate.evaluateWithArguments(expression, returnByValue, utilityScript, values, handles)); } - createHandle(remoteObject: RemoteObject): JSHandle { - return this._delegate.createHandle(this, remoteObject); + getProperties(object: JSHandle): Promise> { + return this._raceAgainstContextDestroyed(this.delegate.getProperties(object)); } - releaseHandle(objectId: ObjectId): Promise { - return this._delegate.releaseHandle(objectId); + releaseHandle(handle: JSHandle): Promise { + return this.delegate.releaseHandle(handle); } adoptIfNeeded(handle: JSHandle): Promise | null { return null; } - utilityScript(): Promise> { + private _utilityScript(): Promise> { if (!this._utilityScriptPromise) { const source = ` (() => { @@ -115,7 +106,11 @@ export class ExecutionContext extends SdkObject { ${utilityScriptSource.source} return new (module.exports.UtilityScript())(${isUnderTest()}); })();`; - this._utilityScriptPromise = this._raceAgainstContextDestroyed(this._delegate.rawEvaluateHandle(source).then(objectId => new JSHandle(this, 'object', 'UtilityScript', objectId))); + this._utilityScriptPromise = this._raceAgainstContextDestroyed(this.delegate.rawEvaluateHandle(this, source)) + .then(handle => { + handle._setPreview('UtilityScript'); + return handle; + }); } return this._utilityScriptPromise; } @@ -129,13 +124,13 @@ export class JSHandle extends SdkObject { __jshandle: T = true as any; readonly _context: ExecutionContext; _disposed = false; - readonly _objectId: ObjectId | undefined; + readonly _objectId: string | undefined; readonly _value: any; private _objectType: string; protected _preview: string; private _previewCallback: ((preview: string) => void) | undefined; - constructor(context: ExecutionContext, type: string, preview: string | undefined, objectId?: ObjectId, value?: any) { + constructor(context: ExecutionContext, type: string, preview: string | undefined, objectId?: string, value?: any) { super(context, 'handle'); this._context = context; this._objectId = objectId; @@ -181,7 +176,7 @@ export class JSHandle extends SdkObject { async getProperties(): Promise> { if (!this._objectId) return new Map(); - return this._context.getProperties(this._context, this._objectId); + return this._context.getProperties(this); } rawValue() { @@ -191,9 +186,8 @@ export class JSHandle extends SdkObject { async jsonValue(): Promise { if (!this._objectId) return this._value; - const utilityScript = await this._context.utilityScript(); const script = `(utilityScript, ...args) => utilityScript.jsonValue(...args)`; - return this._context.evaluateWithArguments(script, true, utilityScript, [true], [this._objectId]); + return this._context.evaluateWithArguments(script, true, [true], [this]); } asElement(): dom.ElementHandle | null { @@ -205,7 +199,7 @@ export class JSHandle extends SdkObject { return; this._disposed = true; if (this._objectId) { - this._context.releaseHandle(this._objectId).catch(e => {}); + this._context.releaseHandle(this).catch(e => {}); if ((globalThis as any).leakedJSHandles) (globalThis as any).leakedJSHandles.delete(this); } @@ -239,7 +233,6 @@ export async function evaluate(context: ExecutionContext, returnByValue: boolean } export async function evaluateExpression(context: ExecutionContext, expression: string, options: { returnByValue?: boolean, isFunction?: boolean }, ...args: any[]): Promise { - const utilityScript = await context.utilityScript(); expression = normalizeEvaluationExpression(expression, options.isFunction); const handles: (Promise)[] = []; const toDispose: Promise[] = []; @@ -263,11 +256,11 @@ export async function evaluateExpression(context: ExecutionContext, expression: return { fallThrough: handle }; })); - const utilityScriptObjectIds: ObjectId[] = []; + const utilityScriptObjects: JSHandle[] = []; for (const handle of await Promise.all(handles)) { if (handle._context !== context) throw new JavaScriptErrorInEvaluate('JSHandles can be evaluated only in the context they were created!'); - utilityScriptObjectIds.push(handle._objectId!); + utilityScriptObjects.push(handle); } // See UtilityScript for arguments. @@ -275,7 +268,7 @@ export async function evaluateExpression(context: ExecutionContext, expression: const script = `(utilityScript, ...args) => utilityScript.evaluate(...args)`; try { - return await context.evaluateWithArguments(script, options.returnByValue || false, utilityScript, utilityScriptValues, utilityScriptObjectIds); + return await context.evaluateWithArguments(script, options.returnByValue || false, utilityScriptValues, utilityScriptObjects); } finally { toDispose.map(handlePromise => handlePromise.then(handle => handle.dispose())); } diff --git a/packages/playwright-core/src/server/launchApp.ts b/packages/playwright-core/src/server/launchApp.ts index d8c81a3169127..84b4c6d6d2fbc 100644 --- a/packages/playwright-core/src/server/launchApp.ts +++ b/packages/playwright-core/src/server/launchApp.ts @@ -16,14 +16,17 @@ import fs from 'fs'; import path from 'path'; -import type { Page } from './page'; -import { findChromiumChannel } from './registry'; + import { isUnderTest } from '../utils'; import { serverSideCallMetadata } from './instrumentation'; -import type * as types from './types'; +import { findChromiumChannel } from './registry'; +import { registryDirectory } from './registry'; + import type { BrowserType } from './browserType'; import type { CRPage } from './chromium/crPage'; -import { registryDirectory } from './registry'; +import type { Page } from './page'; +import type * as types from './types'; + export async function launchApp(browserType: BrowserType, options: { sdkLanguage: string, diff --git a/packages/playwright-core/src/server/localUtils.ts b/packages/playwright-core/src/server/localUtils.ts new file mode 100644 index 0000000000000..c16584b2785c6 --- /dev/null +++ b/packages/playwright-core/src/server/localUtils.ts @@ -0,0 +1,211 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the 'License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import fs from 'fs'; +import os from 'os'; +import path from 'path'; + +import { calculateSha1 } from './utils/crypto'; +import { HarBackend } from './harBackend'; +import { ManualPromise } from '../utils/isomorphic/manualPromise'; +import { ZipFile } from './utils/zipFile'; +import { yauzl, yazl } from '../zipBundle'; +import { serializeClientSideCallMetadata } from '../utils/isomorphic/traceUtils'; +import { assert } from '../utils/isomorphic/assert'; +import { removeFolders } from './utils/fileUtils'; + +import type * as channels from '@protocol/channels'; +import type * as har from '@trace/har'; +import type EventEmitter from 'events'; + + +export type StackSession = { + file: string; + writer: Promise; + tmpDir: string | undefined; + callStacks: channels.ClientSideCallMetadata[]; +}; + +export async function zip(stackSessions: Map, params: channels.LocalUtilsZipParams): Promise { + const promise = new ManualPromise(); + const zipFile = new yazl.ZipFile(); + (zipFile as any as EventEmitter).on('error', error => promise.reject(error)); + + const addFile = (file: string, name: string) => { + try { + if (fs.statSync(file).isFile()) + zipFile.addFile(file, name); + } catch (e) { + } + }; + + for (const entry of params.entries) + addFile(entry.value, entry.name); + + // Add stacks and the sources. + const stackSession = params.stacksId ? stackSessions.get(params.stacksId) : undefined; + if (stackSession?.callStacks.length) { + await stackSession.writer; + if (process.env.PW_LIVE_TRACE_STACKS) { + zipFile.addFile(stackSession.file, 'trace.stacks'); + } else { + const buffer = Buffer.from(JSON.stringify(serializeClientSideCallMetadata(stackSession.callStacks))); + zipFile.addBuffer(buffer, 'trace.stacks'); + } + } + + // Collect sources from stacks. + if (params.includeSources) { + const sourceFiles = new Set(); + for (const { stack } of stackSession?.callStacks || []) { + if (!stack) + continue; + for (const { file } of stack) + sourceFiles.add(file); + } + for (const sourceFile of sourceFiles) + addFile(sourceFile, 'resources/src@' + await calculateSha1(sourceFile) + '.txt'); + } + + if (params.mode === 'write') { + // New file, just compress the entries. + await fs.promises.mkdir(path.dirname(params.zipFile), { recursive: true }); + zipFile.end(undefined, () => { + zipFile.outputStream.pipe(fs.createWriteStream(params.zipFile)) + .on('close', () => promise.resolve()) + .on('error', error => promise.reject(error)); + }); + await promise; + await deleteStackSession(stackSessions, params.stacksId); + return; + } + + // File already exists. Repack and add new entries. + const tempFile = params.zipFile + '.tmp'; + await fs.promises.rename(params.zipFile, tempFile); + + yauzl.open(tempFile, (err, inZipFile) => { + if (err) { + promise.reject(err); + return; + } + assert(inZipFile); + let pendingEntries = inZipFile.entryCount; + inZipFile.on('entry', entry => { + inZipFile.openReadStream(entry, (err, readStream) => { + if (err) { + promise.reject(err); + return; + } + zipFile.addReadStream(readStream!, entry.fileName); + if (--pendingEntries === 0) { + zipFile.end(undefined, () => { + zipFile.outputStream.pipe(fs.createWriteStream(params.zipFile)).on('close', () => { + fs.promises.unlink(tempFile).then(() => { + promise.resolve(); + }).catch(error => promise.reject(error)); + }); + }); + } + }); + }); + }); + await promise; + await deleteStackSession(stackSessions, params.stacksId); +} + +async function deleteStackSession(stackSessions: Map, stacksId?: string) { + const session = stacksId ? stackSessions.get(stacksId) : undefined; + if (!session) + return; + await session.writer; + if (session.tmpDir) + await removeFolders([session.tmpDir]); + stackSessions.delete(stacksId!); +} + +export async function harOpen(harBackends: Map, params: channels.LocalUtilsHarOpenParams): Promise { + let harBackend: HarBackend; + if (params.file.endsWith('.zip')) { + const zipFile = new ZipFile(params.file); + const entryNames = await zipFile.entries(); + const harEntryName = entryNames.find(e => e.endsWith('.har')); + if (!harEntryName) + return { error: 'Specified archive does not have a .har file' }; + const har = await zipFile.read(harEntryName); + const harFile = JSON.parse(har.toString()) as har.HARFile; + harBackend = new HarBackend(harFile, null, zipFile); + } else { + const harFile = JSON.parse(await fs.promises.readFile(params.file, 'utf-8')) as har.HARFile; + harBackend = new HarBackend(harFile, path.dirname(params.file), null); + } + harBackends.set(harBackend.id, harBackend); + return { harId: harBackend.id }; +} + +export async function harLookup(harBackends: Map, params: channels.LocalUtilsHarLookupParams): Promise { + const harBackend = harBackends.get(params.harId); + if (!harBackend) + return { action: 'error', message: `Internal error: har was not opened` }; + return await harBackend.lookup(params.url, params.method, params.headers, params.postData, params.isNavigationRequest); +} + +export async function harClose(harBackends: Map, params: channels.LocalUtilsHarCloseParams): Promise { + const harBackend = harBackends.get(params.harId); + if (harBackend) { + harBackends.delete(harBackend.id); + harBackend.dispose(); + } +} + +export async function harUnzip(params: channels.LocalUtilsHarUnzipParams): Promise { + const dir = path.dirname(params.zipFile); + const zipFile = new ZipFile(params.zipFile); + for (const entry of await zipFile.entries()) { + const buffer = await zipFile.read(entry); + if (entry === 'har.har') + await fs.promises.writeFile(params.harFile, buffer); + else + await fs.promises.writeFile(path.join(dir, entry), buffer); + } + zipFile.close(); + await fs.promises.unlink(params.zipFile); +} + +export async function tracingStarted(stackSessions: Map, params: channels.LocalUtilsTracingStartedParams): Promise { + let tmpDir = undefined; + if (!params.tracesDir) + tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'playwright-tracing-')); + const traceStacksFile = path.join(params.tracesDir || tmpDir!, params.traceName + '.stacks'); + stackSessions.set(traceStacksFile, { callStacks: [], file: traceStacksFile, writer: Promise.resolve(), tmpDir }); + return { stacksId: traceStacksFile }; +} + +export async function traceDiscarded(stackSessions: Map, params: channels.LocalUtilsTraceDiscardedParams): Promise { + await deleteStackSession(stackSessions, params.stacksId); +} + +export async function addStackToTracingNoReply(stackSessions: Map, params: channels.LocalUtilsAddStackToTracingNoReplyParams): Promise { + for (const session of stackSessions.values()) { + session.callStacks.push(params.callData); + if (process.env.PW_LIVE_TRACE_STACKS) { + session.writer = session.writer.then(() => { + const buffer = Buffer.from(JSON.stringify(serializeClientSideCallMetadata(session.callStacks))); + return fs.promises.writeFile(session.file, buffer); + }); + } + } +} diff --git a/packages/playwright-core/src/server/network.ts b/packages/playwright-core/src/server/network.ts index 006f2f4cbff39..e40e0e99a9a20 100644 --- a/packages/playwright-core/src/server/network.ts +++ b/packages/playwright-core/src/server/network.ts @@ -14,18 +14,20 @@ * limitations under the License. */ +import { assert } from '../utils'; +import { BrowserContext } from './browserContext'; +import { APIRequestContext } from './fetch'; +import { SdkObject } from './instrumentation'; +import { ManualPromise } from '../utils/isomorphic/manualPromise'; + import type * as contexts from './browserContext'; -import type * as pages from './page'; import type * as frames from './frames'; +import type * as pages from './page'; import type * as types from './types'; -import type * as channels from '@protocol/channels'; -import { assert } from '../utils'; -import { ManualPromise } from '../utils/manualPromise'; -import { SdkObject } from './instrumentation'; -import type { HeadersArray, NameValue } from '../common/types'; -import { APIRequestContext } from './fetch'; import type { NormalizedContinueOverrides } from './types'; -import { BrowserContext } from './browserContext'; +import type { HeadersArray, NameValue } from '../utils/isomorphic/types'; +import type * as channels from '@protocol/channels'; + export function filterCookies(cookies: channels.NetworkCookie[], urls: string[]): channels.NetworkCookie[] { const parsedURLs = urls.map(s => new URL(s)); diff --git a/packages/playwright-core/src/server/page.ts b/packages/playwright-core/src/server/page.ts index 9b85837b652f6..820c46f4aa324 100644 --- a/packages/playwright-core/src/server/page.ts +++ b/packages/playwright-core/src/server/page.ts @@ -15,37 +15,40 @@ * limitations under the License. */ -import type * as dom from './dom'; -import * as frames from './frames'; -import * as input from './input'; -import * as js from './javascript'; -import type * as network from './network'; -import type * as channels from '@protocol/channels'; -import type { ScreenshotOptions } from './screenshotter'; -import { Screenshotter, validateScreenshotOptions } from './screenshotter'; -import { TimeoutSettings } from '../common/timeoutSettings'; -import type * as types from './types'; +import * as accessibility from './accessibility'; import { BrowserContext } from './browserContext'; import { ConsoleMessage } from './console'; -import * as accessibility from './accessibility'; +import { TargetClosedError, TimeoutError } from './errors'; import { FileChooser } from './fileChooser'; -import type { Progress } from './progress'; -import { ProgressController } from './progress'; -import { LongStandingScope, assert, compressCallLog, createGuid, trimStringWithEllipsis } from '../utils'; -import { ManualPromise } from '../utils/manualPromise'; -import { debugLogger } from '../utils/debugLogger'; -import type { ImageComparatorOptions } from '../utils/comparators'; -import { getComparator } from '../utils/comparators'; -import type { CallMetadata } from './instrumentation'; +import * as frames from './frames'; +import { helper } from './helper'; +import * as input from './input'; import { SdkObject } from './instrumentation'; -import type { Artifact } from './artifact'; -import type { TimeoutOptions } from '../common/types'; -import { isInvalidSelectorError } from '../utils/isomorphic/selectorParser'; import { parseEvaluationResultValue, source } from './isomorphic/utilityScriptSerializers'; -import type { SerializedValue } from './isomorphic/utilityScriptSerializers'; -import { TargetClosedError, TimeoutError } from './errors'; +import * as js from './javascript'; +import { ProgressController } from './progress'; +import { Screenshotter, validateScreenshotOptions } from './screenshotter'; +import { TimeoutSettings } from './timeoutSettings'; +import { LongStandingScope, assert, trimStringWithEllipsis } from '../utils'; +import { createGuid } from './utils/crypto'; import { asLocator } from '../utils'; -import { helper } from './helper'; +import { getComparator } from './utils/comparators'; +import { debugLogger } from './utils/debugLogger'; +import { isInvalidSelectorError } from '../utils/isomorphic/selectorParser'; +import { ManualPromise } from '../utils/isomorphic/manualPromise'; +import { compressCallLog } from './callLog'; + +import type { Artifact } from './artifact'; +import type * as dom from './dom'; +import type { CallMetadata } from './instrumentation'; +import type { SerializedValue } from './isomorphic/utilityScriptSerializers'; +import type * as network from './network'; +import type { Progress } from './progress'; +import type { ScreenshotOptions } from './screenshotter'; +import type * as types from './types'; +import type { TimeoutOptions } from '../utils/isomorphic/types'; +import type { ImageComparatorOptions } from './utils/comparators'; +import type * as channels from '@protocol/channels'; export interface PageDelegate { readonly rawMouse: input.RawMouse; @@ -72,12 +75,10 @@ export interface PageDelegate { setBackgroundColor(color?: { r: number; g: number; b: number; a: number; }): Promise; takeScreenshot(progress: Progress, format: string, documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined, fitsViewport: boolean, scale: 'css' | 'device'): Promise; - isElementHandle(remoteObject: any): boolean; adoptElementHandle(handle: dom.ElementHandle, to: dom.FrameExecutionContext): Promise>; getContentFrame(handle: dom.ElementHandle): Promise; // Only called for frame owner elements. getOwnerFrame(handle: dom.ElementHandle): Promise; // Returns frameId. getContentQuads(handle: dom.ElementHandle): Promise; - setInputFiles(handle: dom.ElementHandle, files: types.FilePayload[]): Promise; setInputFilePaths(handle: dom.ElementHandle, files: string[]): Promise; getBoundingBox(handle: dom.ElementHandle): Promise; getFrameElement(frame: frames.Frame): Promise; @@ -107,6 +108,7 @@ type EmulatedMedia = { colorScheme: types.ColorScheme; reducedMotion: types.ReducedMotion; forcedColors: types.ForcedColors; + contrast: types.Contrast; }; type ExpectScreenshotOptions = ImageComparatorOptions & ScreenshotOptions & { @@ -530,6 +532,8 @@ export class Page extends SdkObject { this._emulatedMedia.reducedMotion = options.reducedMotion; if (options.forcedColors !== undefined) this._emulatedMedia.forcedColors = options.forcedColors; + if (options.contrast !== undefined) + this._emulatedMedia.contrast = options.contrast; await this._delegate.updateEmulateMedia(); } @@ -541,6 +545,7 @@ export class Page extends SdkObject { colorScheme: this._emulatedMedia.colorScheme !== undefined ? this._emulatedMedia.colorScheme : contextOptions.colorScheme ?? 'light', reducedMotion: this._emulatedMedia.reducedMotion !== undefined ? this._emulatedMedia.reducedMotion : contextOptions.reducedMotion ?? 'no-preference', forcedColors: this._emulatedMedia.forcedColors !== undefined ? this._emulatedMedia.forcedColors : contextOptions.forcedColors ?? 'none', + contrast: this._emulatedMedia.contrast !== undefined ? this._emulatedMedia.contrast : contextOptions.contrast ?? 'no-preference', }; } @@ -828,6 +833,7 @@ export class Worker extends SdkObject { _createExecutionContext(delegate: js.ExecutionContextDelegate) { this._existingExecutionContext = new js.ExecutionContext(this, delegate, 'worker'); this._executionContextCallback(this._existingExecutionContext); + return this._existingExecutionContext; } url(): string { diff --git a/packages/playwright-core/src/server/pipeTransport.ts b/packages/playwright-core/src/server/pipeTransport.ts index b5755d098d912..ba811e606e496 100644 --- a/packages/playwright-core/src/server/pipeTransport.ts +++ b/packages/playwright-core/src/server/pipeTransport.ts @@ -15,9 +15,10 @@ * limitations under the License. */ -import type { ConnectionTransport, ProtocolRequest, ProtocolResponse } from './transport'; import { makeWaitForNextTask } from '../utils'; -import { debugLogger } from '../utils/debugLogger'; +import { debugLogger } from './utils/debugLogger'; + +import type { ConnectionTransport, ProtocolRequest, ProtocolResponse } from './transport'; export class PipeTransport implements ConnectionTransport { private _pipeRead: NodeJS.ReadableStream; diff --git a/packages/playwright-core/src/server/playwright.ts b/packages/playwright-core/src/server/playwright.ts index 722400b6fcf3e..a1092361ae27a 100644 --- a/packages/playwright-core/src/server/playwright.ts +++ b/packages/playwright-core/src/server/playwright.ts @@ -14,22 +14,24 @@ * limitations under the License. */ +import { debugLogger } from '../utils'; import { Android } from './android/android'; import { AdbBackend } from './android/backendAdb'; -import type { Browser } from './browser'; +import { BidiChromium } from './bidi/bidiChromium'; +import { BidiFirefox } from './bidi/bidiFirefox'; import { Chromium } from './chromium/chromium'; +import { DebugController } from './debugController'; import { Electron } from './electron/electron'; import { Firefox } from './firefox/firefox'; +import { SdkObject, createInstrumentation } from './instrumentation'; import { Selectors } from './selectors'; import { WebKit } from './webkit/webkit'; + +import type { BrowserType } from './browserType'; +import type { Language } from '../utils'; +import type { Browser } from './browser'; import type { CallMetadata } from './instrumentation'; -import { createInstrumentation, SdkObject } from './instrumentation'; -import { debugLogger, type Language } from '../utils'; import type { Page } from './page'; -import { DebugController } from './debugController'; -import type { BrowserType } from './browserType'; -import { BidiChromium } from './bidi/bidiChromium'; -import { BidiFirefox } from './bidi/bidiFirefox'; type PlaywrightOptions = { socksProxyPort?: number; diff --git a/packages/playwright-core/src/server/progress.ts b/packages/playwright-core/src/server/progress.ts index d92c5ed226f8e..16dcc6fb1f501 100644 --- a/packages/playwright-core/src/server/progress.ts +++ b/packages/playwright-core/src/server/progress.ts @@ -16,9 +16,10 @@ import { TimeoutError } from './errors'; import { assert, monotonicTime } from '../utils'; -import type { LogName } from '../utils/debugLogger'; +import { ManualPromise } from '../utils/isomorphic/manualPromise'; + import type { CallMetadata, Instrumentation, SdkObject } from './instrumentation'; -import { ManualPromise } from '../utils/manualPromise'; +import type { LogName } from './utils/debugLogger'; export interface Progress { log(message: string): void; diff --git a/packages/playwright-core/src/server/protocolError.ts b/packages/playwright-core/src/server/protocolError.ts index 1f999b7c640b9..9ef856c2eb9fb 100644 --- a/packages/playwright-core/src/server/protocolError.ts +++ b/packages/playwright-core/src/server/protocolError.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { rewriteErrorMessage } from '../utils/stackTrace'; +import { rewriteErrorMessage } from '../utils/isomorphic/stackTrace'; export class ProtocolError extends Error { type: 'error' | 'closed' | 'crashed'; diff --git a/packages/playwright-core/src/server/recorder.ts b/packages/playwright-core/src/server/recorder.ts index 59705c2eb4832..aac9ab696b9d5 100644 --- a/packages/playwright-core/src/server/recorder.ts +++ b/packages/playwright-core/src/server/recorder.ts @@ -14,24 +14,27 @@ * limitations under the License. */ -import type * as channels from '@protocol/channels'; -import type { CallLog, CallLogStatus, ElementInfo, EventData, Mode, OverlayState, Source, UIState } from '@recorder/recorderTypes'; -import * as fs from 'fs'; -import type { Point } from '../common/types'; +import fs from 'fs'; + import * as consoleApiSource from '../generated/consoleApiSource'; import { isUnderTest } from '../utils'; -import { locatorOrSelectorAsSelector } from '../utils/isomorphic/locatorParser'; import { BrowserContext } from './browserContext'; -import { type Language } from './codegen/types'; import { Debugger } from './debugger'; -import type { CallMetadata, InstrumentationListener, SdkObject } from './instrumentation'; import { ContextRecorder, generateFrameSelector } from './recorder/contextRecorder'; -import type { IRecorderAppFactory, IRecorderApp, IRecorder } from './recorder/recorderFrontend'; import { buildFullSelector, metadataToCallLog } from './recorder/recorderUtils'; -import type * as actions from '@recorder/actions'; +import { locatorOrSelectorAsSelector } from '../utils/isomorphic/locatorParser'; import { stringifySelector } from '../utils/isomorphic/selectorParser'; + +import type { Language } from './codegen/types'; import type { Frame } from './frames'; +import type { CallMetadata, InstrumentationListener, SdkObject } from './instrumentation'; +import type { Page } from './page'; +import type { IRecorder, IRecorderApp, IRecorderAppFactory } from './recorder/recorderFrontend'; +import type { Point } from '../utils/isomorphic/types'; import type { AriaTemplateNode } from '@isomorphic/ariaSnapshot'; +import type * as channels from '@protocol/channels'; +import type * as actions from '@recorder/actions'; +import type { CallLog, CallLogStatus, ElementInfo, EventData, Mode, OverlayState, Source, UIState } from '@recorder/recorderTypes'; const recorderSymbol = Symbol('recorderSymbol'); @@ -148,6 +151,7 @@ export class Recorder implements InstrumentationListener, IRecorder { this._context.instrumentation.removeListener(this); this._recorderApp?.close().catch(() => {}); }); + this._contextRecorder.on(ContextRecorder.Events.Change, (data: { sources: Source[], actions: actions.ActionInContext[] }) => { this._recorderSources = data.sources; recorderApp.setActions(data.actions, data.sources); @@ -346,7 +350,8 @@ export class Recorder implements InstrumentationListener, IRecorder { } private _pushAllSources() { - this._recorderApp?.setSources([...this._recorderSources, ...this._userSources.values()]); + const primaryPage: Page | undefined = this._context.pages()[0]; + this._recorderApp?.setSources([...this._recorderSources, ...this._userSources.values()], primaryPage?.mainFrame().url()); } async onBeforeInputAction(sdkObject: SdkObject, metadata: CallMetadata) { diff --git a/packages/playwright-core/src/server/recorder/DEPS.list b/packages/playwright-core/src/server/recorder/DEPS.list index b130c181dc1ec..6151537ccb4af 100644 --- a/packages/playwright-core/src/server/recorder/DEPS.list +++ b/packages/playwright-core/src/server/recorder/DEPS.list @@ -4,7 +4,7 @@ ../codegen/languages.ts ../isomorphic/** ../registry/** -../../common/ +../utils/** ../../generated/pollingRecorderSource.ts ../../protocol/ ../../utils/** diff --git a/packages/playwright-core/src/server/recorder/chat.ts b/packages/playwright-core/src/server/recorder/chat.ts index 5b3917c7352e1..c3ad0238f7f00 100644 --- a/packages/playwright-core/src/server/recorder/chat.ts +++ b/packages/playwright-core/src/server/recorder/chat.ts @@ -15,6 +15,7 @@ */ import { WebSocketTransport } from '../transport'; + import type { ConnectionTransport, ProtocolResponse } from '../transport'; export type ChatMessage = { diff --git a/packages/playwright-core/src/server/recorder/contextRecorder.ts b/packages/playwright-core/src/server/recorder/contextRecorder.ts index 292271acd5832..cede7bb28a681 100644 --- a/packages/playwright-core/src/server/recorder/contextRecorder.ts +++ b/packages/playwright-core/src/server/recorder/contextRecorder.ts @@ -14,23 +14,26 @@ * limitations under the License. */ -import type * as channels from '@protocol/channels'; -import type { Source } from '@recorder/recorderTypes'; import { EventEmitter } from 'events'; + +import { RecorderCollection } from './recorderCollection'; import * as recorderSource from '../../generated/pollingRecorderSource'; -import { eventsHelper, monotonicTime, quoteCSSAttributeValue, type RegisteredListener } from '../../utils'; -import { raceAgainstDeadline } from '../../utils/timeoutRunner'; +import { eventsHelper, monotonicTime, quoteCSSAttributeValue } from '../../utils'; +import { raceAgainstDeadline } from '../../utils/isomorphic/timeoutRunner'; import { BrowserContext } from '../browserContext'; -import type { LanguageGeneratorOptions, Language, LanguageGenerator } from '../codegen/types'; import { languageSet } from '../codegen/languages'; -import type { Dialog } from '../dialog'; import { Frame } from '../frames'; import { Page } from '../page'; -import type * as actions from '@recorder/actions'; import { ThrottledFile } from './throttledFile'; -import { RecorderCollection } from './recorderCollection'; import { generateCode } from '../codegen/language'; +import type { RegisteredListener } from '../../utils'; +import type { Language, LanguageGenerator, LanguageGeneratorOptions } from '../codegen/types'; +import type { Dialog } from '../dialog'; +import type * as channels from '@protocol/channels'; +import type * as actions from '@recorder/actions'; +import type { Source } from '@recorder/recorderTypes'; + type BindingSource = { frame: Frame, page: Page }; export interface ContextRecorderDelegate { diff --git a/packages/playwright-core/src/server/recorder/recorderApp.ts b/packages/playwright-core/src/server/recorder/recorderApp.ts index f8971531cf81e..53563b71a01b8 100644 --- a/packages/playwright-core/src/server/recorder/recorderApp.ts +++ b/packages/playwright-core/src/server/recorder/recorderApp.ts @@ -14,20 +14,22 @@ * limitations under the License. */ +import { EventEmitter } from 'events'; import fs from 'fs'; import path from 'path'; -import type { Page } from '../page'; -import { ProgressController } from '../progress'; -import { EventEmitter } from 'events'; -import { serverSideCallMetadata } from '../instrumentation'; -import type { CallLog, ElementInfo, Mode, Source } from '@recorder/recorderTypes'; -import { isUnderTest } from '../../utils'; + +import { isUnderTest } from '../utils/debug'; import { mime } from '../../utilsBundle'; +import { serverSideCallMetadata } from '../instrumentation'; import { syncLocalStorageWithSettings } from '../launchApp'; -import type { BrowserContext } from '../browserContext'; import { launchApp } from '../launchApp'; +import { ProgressController } from '../progress'; + +import type { BrowserContext } from '../browserContext'; +import type { Page } from '../page'; import type { IRecorder, IRecorderApp, IRecorderAppFactory } from './recorderFrontend'; import type * as actions from '@recorder/actions'; +import type { CallLog, ElementInfo, Mode, Source } from '@recorder/recorderTypes'; export class EmptyRecorderApp extends EventEmitter implements IRecorderApp { wsEndpointForTest: undefined; @@ -37,7 +39,7 @@ export class EmptyRecorderApp extends EventEmitter implements IRecorderApp { async setRunningFile(file: string | undefined): Promise {} async elementPicked(elementInfo: ElementInfo, userGesture?: boolean): Promise {} async updateCallLogs(callLogs: CallLog[]): Promise {} - async setSources(sources: Source[]): Promise {} + async setSources(sources: Source[], primaryPageURL: string | undefined): Promise {} async setActions(actions: actions.ActionInContext[], sources: Source[]): Promise {} } @@ -143,10 +145,10 @@ export class RecorderApp extends EventEmitter implements IRecorderApp { }).toString(), { isFunction: true }, paused).catch(() => {}); } - async setSources(sources: Source[]): Promise { - await this._page.mainFrame().evaluateExpression(((sources: Source[]) => { - window.playwrightSetSources(sources); - }).toString(), { isFunction: true }, sources).catch(() => {}); + async setSources(sources: Source[], primaryPageURL: string | undefined): Promise { + await this._page.mainFrame().evaluateExpression((({ sources, primaryPageURL }: { sources: Source[], primaryPageURL: string | undefined }) => { + window.playwrightSetSources(sources, primaryPageURL); + }).toString(), { isFunction: true }, { sources, primaryPageURL }).catch(() => {}); // Testing harness for runCLI mode. if (process.env.PWTEST_CLI_IS_UNDER_TEST && sources.length) { diff --git a/packages/playwright-core/src/server/recorder/recorderCollection.ts b/packages/playwright-core/src/server/recorder/recorderCollection.ts index 162d5d6813b28..b8802a920acf9 100644 --- a/packages/playwright-core/src/server/recorder/recorderCollection.ts +++ b/packages/playwright-core/src/server/recorder/recorderCollection.ts @@ -15,14 +15,16 @@ */ import { EventEmitter } from 'events'; + +import { performAction } from './recorderRunner'; +import { collapseActions } from './recorderUtils'; +import { isUnderTest } from '../utils/debug'; +import { monotonicTime } from '../../utils/isomorphic/time'; + +import type { Signal } from '../../../../recorder/src/actions'; import type { Frame } from '../frames'; import type { Page } from '../page'; -import type { Signal } from '../../../../recorder/src/actions'; import type * as actions from '@recorder/actions'; -import { monotonicTime } from '../../utils/time'; -import { collapseActions } from './recorderUtils'; -import { performAction } from './recorderRunner'; -import { isUnderTest } from '../../utils/debug'; export class RecorderCollection extends EventEmitter { private _actions: actions.ActionInContext[] = []; @@ -85,7 +87,7 @@ export class RecorderCollection extends EventEmitter { let generateGoto = false; if (!lastAction) generateGoto = true; - else if (lastAction.action.name !== 'click' && lastAction.action.name !== 'press') + else if (lastAction.action.name !== 'click' && lastAction.action.name !== 'press' && lastAction.action.name !== 'fill') generateGoto = true; else if (timestamp - lastAction.startTime > signalThreshold) generateGoto = true; diff --git a/packages/playwright-core/src/server/recorder/recorderFrontend.ts b/packages/playwright-core/src/server/recorder/recorderFrontend.ts index b3dc0daad9bd8..1b97541cb7360 100644 --- a/packages/playwright-core/src/server/recorder/recorderFrontend.ts +++ b/packages/playwright-core/src/server/recorder/recorderFrontend.ts @@ -15,7 +15,7 @@ */ import type * as actions from '@recorder/actions'; -import type { CallLog, Mode, Source, ElementInfo } from '@recorder/recorderTypes'; +import type { CallLog, ElementInfo, Mode, Source } from '@recorder/recorderTypes'; import type { EventEmitter } from 'events'; export interface IRecorder { @@ -32,7 +32,7 @@ export interface IRecorderApp extends EventEmitter { setRunningFile(file: string | undefined): Promise; elementPicked(elementInfo: ElementInfo, userGesture?: boolean): Promise; updateCallLogs(callLogs: CallLog[]): Promise; - setSources(sources: Source[]): Promise; + setSources(sources: Source[], primaryPageURL: string | undefined): Promise; setActions(actions: actions.ActionInContext[], sources: Source[]): Promise; } diff --git a/packages/playwright-core/src/server/recorder/recorderRunner.ts b/packages/playwright-core/src/server/recorder/recorderRunner.ts index bb225ec5aba7b..5936060609765 100644 --- a/packages/playwright-core/src/server/recorder/recorderRunner.ts +++ b/packages/playwright-core/src/server/recorder/recorderRunner.ts @@ -17,10 +17,11 @@ import { serializeExpectedTextValues } from '../../utils'; import { toKeyboardModifiers } from '../codegen/language'; import { serverSideCallMetadata } from '../instrumentation'; +import { buildFullSelector, mainFrameForAction } from './recorderUtils'; + import type { Page } from '../page'; -import type * as actions from '@recorder/actions'; import type * as types from '../types'; -import { buildFullSelector, mainFrameForAction } from './recorderUtils'; +import type * as actions from '@recorder/actions'; export async function performAction(pageAliases: Map, actionInContext: actions.ActionInContext) { const callMetadata = serverSideCallMetadata(); diff --git a/packages/playwright-core/src/server/recorder/recorderUtils.ts b/packages/playwright-core/src/server/recorder/recorderUtils.ts index 77ef329d2720d..39e8c07557dfe 100644 --- a/packages/playwright-core/src/server/recorder/recorderUtils.ts +++ b/packages/playwright-core/src/server/recorder/recorderUtils.ts @@ -14,11 +14,11 @@ * limitations under the License. */ +import type { Frame } from '../frames'; import type { CallMetadata } from '../instrumentation'; -import type { CallLog, CallLogStatus } from '@recorder/recorderTypes'; import type { Page } from '../page'; -import type { Frame } from '../frames'; import type * as actions from '@recorder/actions'; +import type { CallLog, CallLogStatus } from '@recorder/recorderTypes'; export function buildFullSelector(framePath: string[], selector: string) { return [...framePath, selector].join(' >> internal:control=enter-frame >> '); diff --git a/packages/playwright-core/src/server/recorder/throttledFile.ts b/packages/playwright-core/src/server/recorder/throttledFile.ts index 4a34f41a0c5af..e0d1c935681a9 100644 --- a/packages/playwright-core/src/server/recorder/throttledFile.ts +++ b/packages/playwright-core/src/server/recorder/throttledFile.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import * as fs from 'fs'; +import fs from 'fs'; export class ThrottledFile { private _file: string; diff --git a/packages/playwright-core/src/server/registry/browserFetcher.ts b/packages/playwright-core/src/server/registry/browserFetcher.ts index 3a6e36b42dacf..38a3e860c6309 100644 --- a/packages/playwright-core/src/server/registry/browserFetcher.ts +++ b/packages/playwright-core/src/server/registry/browserFetcher.ts @@ -15,16 +15,19 @@ * limitations under the License. */ +import * as childProcess from 'child_process'; import fs from 'fs'; import os from 'os'; import path from 'path'; -import childProcess from 'child_process'; -import { existsAsync } from '../../utils/fileUtils'; -import { debugLogger } from '../../utils/debugLogger'; -import { ManualPromise } from '../../utils/manualPromise'; -import { colors, progress as ProgressBar } from '../../utilsBundle'; + +import { debugLogger } from '../utils/debugLogger'; +import { ManualPromise } from '../../utils/isomorphic/manualPromise'; +import { getUserAgent } from '../utils/userAgent'; +import { progress as ProgressBar, colors } from '../../utilsBundle'; +import { existsAsync } from '../utils/fileUtils'; + import { browserDirectoryToMarkerFilePath } from '.'; -import { getUserAgent } from '../../utils/userAgent'; + import type { DownloadParams } from './oopDownloadBrowserMain'; export async function downloadBrowserWithProgressBar(title: string, browserDirectory: string, executablePath: string | undefined, downloadURLs: string[], downloadFileName: string, downloadConnectionTimeout: number): Promise { diff --git a/packages/playwright-core/src/server/registry/dependencies.ts b/packages/playwright-core/src/server/registry/dependencies.ts index 4aa568a6f92f9..2b97d02d20a8b 100644 --- a/packages/playwright-core/src/server/registry/dependencies.ts +++ b/packages/playwright-core/src/server/registry/dependencies.ts @@ -14,16 +14,18 @@ * limitations under the License. */ +import * as childProcess from 'child_process'; import fs from 'fs'; +import os from 'os'; import path from 'path'; -import * as os from 'os'; -import childProcess from 'child_process'; -import * as utils from '../../utils'; -import { spawnAsync } from '../../utils/spawnAsync'; -import { hostPlatform, isOfficiallySupportedPlatform } from '../../utils/hostPlatform'; -import { buildPlaywrightCLICommand, registry } from '.'; + import { deps } from './nativeDeps'; -import { getPlaywrightVersion } from '../../utils/userAgent'; +import { wrapInASCIIBox } from '../utils/ascii'; +import { hostPlatform, isOfficiallySupportedPlatform } from '../utils/hostPlatform'; +import { spawnAsync } from '../utils/spawnAsync'; +import { getPlaywrightVersion } from '../utils/userAgent'; + +import { buildPlaywrightCLICommand, registry } from '.'; const BIN_DIRECTORY = path.join(__dirname, '..', '..', '..', 'bin'); const languageBindingVersion = process.env.PW_CLI_DISPLAY_VERSION || require('../../../package.json').version; @@ -269,7 +271,7 @@ export async function validateDependenciesLinux(sdkLanguage: string, linuxLddDir ]); } - throw new Error('\n' + utils.wrapInASCIIBox(errorLines.join('\n'), 1)); + throw new Error('\n' + wrapInASCIIBox(errorLines.join('\n'), 1)); } function isSharedLib(basename: string) { diff --git a/packages/playwright-core/src/server/registry/index.ts b/packages/playwright-core/src/server/registry/index.ts index c4d7f2ffbb7cf..e7687d1840c7a 100644 --- a/packages/playwright-core/src/server/registry/index.ts +++ b/packages/playwright-core/src/server/registry/index.ts @@ -15,23 +15,28 @@ * limitations under the License. */ -import * as os from 'os'; +import fs from 'fs'; +import os from 'os'; import path from 'path'; import * as util from 'util'; -import * as fs from 'fs'; + +import { downloadBrowserWithProgressBar, logPolitely } from './browserFetcher'; +import { dockerVersion, readDockerVersionSync, transformCommandsForRoot } from './dependencies'; +import { installDependenciesLinux, installDependenciesWindows, validateDependenciesLinux, validateDependenciesWindows } from './dependencies'; +import { calculateSha1, getAsBooleanFromENV, getFromENV, getPackageManagerExecCommand } from '../../utils'; +import { wrapInASCIIBox } from '../utils/ascii'; +import { debugLogger } from '../utils/debugLogger'; +import { hostPlatform, isOfficiallySupportedPlatform } from '../utils/hostPlatform'; +import { fetchData } from '../utils/network'; +import { spawnAsync } from '../utils/spawnAsync'; +import { getEmbedderName } from '../utils/userAgent'; import { lockfile } from '../../utilsBundle'; -import { fetchData } from '../../utils/network'; -import { getEmbedderName } from '../../utils/userAgent'; -import { getFromENV, getAsBooleanFromENV, calculateSha1, wrapInASCIIBox, getPackageManagerExecCommand } from '../../utils'; -import { removeFolders, existsAsync, canAccessFile } from '../../utils/fileUtils'; -import { type HostPlatform, hostPlatform, isOfficiallySupportedPlatform } from '../../utils/hostPlatform'; -import { spawnAsync } from '../../utils/spawnAsync'; +import { canAccessFile, existsAsync, removeFolders } from '../utils/fileUtils'; + import type { DependencyGroup } from './dependencies'; -import { transformCommandsForRoot, dockerVersion, readDockerVersionSync } from './dependencies'; -import { installDependenciesLinux, installDependenciesWindows, validateDependenciesLinux, validateDependenciesWindows } from './dependencies'; -import { downloadBrowserWithProgressBar, logPolitely } from './browserFetcher'; +import type { HostPlatform } from '../utils/hostPlatform'; + export { writeDockerVersion } from './dependencies'; -import { debugLogger } from '../../utils/debugLogger'; const PACKAGE_PATH = path.join(__dirname, '..', '..', '..'); const BIN_PATH = path.join(__dirname, '..', '..', '..', 'bin'); @@ -445,14 +450,7 @@ type BrowsersJSONDescriptor = { }; function readDescriptors(browsersJSON: BrowsersJSON): BrowsersJSONDescriptor[] { - const headlessShells: BrowsersJSON['browsers'] = []; - for (const browserName of ['chromium', 'chromium-tip-of-tree']) { - headlessShells.push({ - ...browsersJSON.browsers.find(browser => browser.name === browserName)!, - name: `${browserName}-headless-shell`, - }); - } - return [...browsersJSON.browsers, ...headlessShells].map(obj => { + return (browsersJSON['browsers']).map(obj => { const name = obj.name; const revisionOverride = (obj.revisionOverrides || {})[hostPlatform]; const revision = revisionOverride || obj.revision; diff --git a/packages/playwright-core/src/server/registry/oopDownloadBrowserMain.ts b/packages/playwright-core/src/server/registry/oopDownloadBrowserMain.ts index 247581277ea4d..770a6334fe999 100644 --- a/packages/playwright-core/src/server/registry/oopDownloadBrowserMain.ts +++ b/packages/playwright-core/src/server/registry/oopDownloadBrowserMain.ts @@ -16,8 +16,9 @@ import fs from 'fs'; import path from 'path'; -import { httpRequest } from '../../utils/network'; -import { ManualPromise } from '../../utils/manualPromise'; + +import { ManualPromise } from '../../utils/isomorphic/manualPromise'; +import { httpRequest } from '../utils/network'; import { extract } from '../../zipBundle'; export type DownloadParams = { diff --git a/packages/playwright-core/src/server/screenshotter.ts b/packages/playwright-core/src/server/screenshotter.ts index 485560b5395a4..77c83b8325f19 100644 --- a/packages/playwright-core/src/server/screenshotter.ts +++ b/packages/playwright-core/src/server/screenshotter.ts @@ -15,16 +15,18 @@ * limitations under the License. */ -import type * as dom from './dom'; -import type { Rect } from '../common/types'; import { helper } from './helper'; -import type { Page } from './page'; +import { assert } from '../utils'; +import { MultiMap } from '../utils/isomorphic/multimap'; + +import type * as dom from './dom'; import type { Frame } from './frames'; -import type { ParsedSelector } from '../utils/isomorphic/selectorParser'; -import type * as types from './types'; +import type { Page } from './page'; import type { Progress } from './progress'; -import { assert } from '../utils'; -import { MultiMap } from '../utils/multimap'; +import type * as types from './types'; +import type { Rect } from '../utils/isomorphic/types'; +import type { ParsedSelector } from '../utils/isomorphic/selectorParser'; + declare global { interface Window { diff --git a/packages/playwright-core/src/server/selectors.ts b/packages/playwright-core/src/server/selectors.ts index b54a0269a56b4..886108b972e84 100644 --- a/packages/playwright-core/src/server/selectors.ts +++ b/packages/playwright-core/src/server/selectors.ts @@ -14,8 +14,10 @@ * limitations under the License. */ -import { visitAllSelectorParts, InvalidSelectorError, type ParsedSelector, parseSelector, stringifySelector } from '../utils/isomorphic/selectorParser'; -import { createGuid } from '../utils'; +import { createGuid } from './utils/crypto'; +import { InvalidSelectorError, parseSelector, stringifySelector, visitAllSelectorParts } from '../utils/isomorphic/selectorParser'; + +import type { ParsedSelector } from '../utils/isomorphic/selectorParser'; export class Selectors { private readonly _builtinEngines: Set; @@ -39,7 +41,7 @@ export class Selectors { 'internal:has', 'internal:has-not', 'internal:has-text', 'internal:has-not-text', 'internal:and', 'internal:or', 'internal:chain', - 'role', 'internal:attr', 'internal:label', 'internal:text', 'internal:role', 'internal:testid', + 'role', 'internal:attr', 'internal:label', 'internal:text', 'internal:role', 'internal:testid', 'internal:aria-id' ]); this._builtinEnginesInMainWorld = new Set([ '_react', '_vue', diff --git a/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts b/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts index 2517ea24ce0fa..a68cb88abb779 100644 --- a/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts +++ b/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts @@ -14,20 +14,22 @@ * limitations under the License. */ -import net from 'net'; +import { EventEmitter } from 'events'; import http2 from 'http2'; -import type https from 'https'; -import tls from 'tls'; +import net from 'net'; import stream from 'stream'; -import { createSocket, createTLSSocket } from '../utils/happy-eyeballs'; -import { escapeHTML, generateSelfSignedCertificate, ManualPromise, rewriteErrorMessage } from '../utils'; -import type { SocksSocketClosedPayload, SocksSocketDataPayload, SocksSocketRequestedPayload } from '../common/socksProxy'; -import { SocksProxy } from '../common/socksProxy'; -import type * as types from './types'; -import { debugLogger } from '../utils/debugLogger'; -import { createProxyAgent } from './fetch'; -import { EventEmitter } from 'events'; +import tls from 'tls'; + +import { SocksProxy } from './utils/socksProxy'; +import { ManualPromise, escapeHTML, generateSelfSignedCertificate, rewriteErrorMessage } from '../utils'; import { verifyClientCertificates } from './browserContext'; +import { createProxyAgent } from './fetch'; +import { debugLogger } from './utils/debugLogger'; +import { createSocket, createTLSSocket } from './utils/happyEyeballs'; + +import type * as types from './types'; +import type { SocksSocketClosedPayload, SocksSocketDataPayload, SocksSocketRequestedPayload } from './utils/socksProxy'; +import type https from 'https'; let dummyServerTlsOptions: tls.TlsOptions | undefined = undefined; function loadDummyServerCertsIfNeeded() { @@ -98,7 +100,7 @@ class SocksProxyConnection { async connect() { if (this.socksProxy.proxyAgentFromOptions) - this.target = await this.socksProxy.proxyAgentFromOptions.connect(new EventEmitter() as any, { host: rewriteToLocalhostIfNeeded(this.host), port: this.port, secureEndpoint: false }); + this.target = await this.socksProxy.proxyAgentFromOptions.callback(new EventEmitter() as any, { host: rewriteToLocalhostIfNeeded(this.host), port: this.port, secureEndpoint: false }); else this.target = await createSocket(rewriteToLocalhostIfNeeded(this.host), this.port); diff --git a/packages/playwright-core/src/server/socksInterceptor.ts b/packages/playwright-core/src/server/socksInterceptor.ts index 6b29636a004f0..c29981204fa10 100644 --- a/packages/playwright-core/src/server/socksInterceptor.ts +++ b/packages/playwright-core/src/server/socksInterceptor.ts @@ -14,12 +14,15 @@ * limitations under the License. */ -import * as socks from '../common/socksProxy'; import EventEmitter from 'events'; -import type * as channels from '@protocol/channels'; + +import * as socks from './utils/socksProxy'; +import { ValidationError, findValidator } from '../protocol/validator'; +import { isUnderTest } from './utils/debug'; + import type { WebSocketTransport } from './transport'; -import { findValidator, ValidationError } from '../protocol/validator'; import type { ValidatorContext } from '../protocol/validator'; +import type * as channels from '@protocol/channels'; export class SocksInterceptor { private _handler: socks.SocksProxyHandler; @@ -40,7 +43,7 @@ export class SocksInterceptor { const id = --lastId; this._ids.add(id); const validator = findValidator('SocksSupport', prop, 'Params'); - params = validator(params, '', { tChannelImpl: tChannelForSocks, binary: 'toBase64' }); + params = validator(params, '', { tChannelImpl: tChannelForSocks, binary: 'toBase64', isUnderTest }); transport.send({ id, guid: this._socksSupportObjectGuid, method: prop, params, metadata: { stack: [], apiName: '', internal: true } } as any); } catch (e) { } @@ -72,7 +75,7 @@ export class SocksInterceptor { } if (this._socksSupportObjectGuid && message.guid === this._socksSupportObjectGuid) { const validator = findValidator('SocksSupport', message.method, 'Event'); - const params = validator(message.params, '', { tChannelImpl: tChannelForSocks, binary: 'fromBase64' }); + const params = validator(message.params, '', { tChannelImpl: tChannelForSocks, binary: 'fromBase64', isUnderTest }); this._channel.emit(message.method, params); return true; } diff --git a/packages/playwright-core/src/server/storageScript.ts b/packages/playwright-core/src/server/storageScript.ts new file mode 100644 index 0000000000000..6ed162587b795 --- /dev/null +++ b/packages/playwright-core/src/server/storageScript.ts @@ -0,0 +1,171 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { source } from './isomorphic/utilityScriptSerializers'; +import type * as channels from '@protocol/channels'; + +export type Storage = Omit; + +export async function collect(serializers: ReturnType, isFirefox: boolean, recordIndexedDB: boolean): Promise { + async function collectDB(dbInfo: IDBDatabaseInfo) { + if (!dbInfo.name) + throw new Error('Database name is empty'); + if (!dbInfo.version) + throw new Error('Database version is unset'); + + function idbRequestToPromise(request: T) { + return new Promise((resolve, reject) => { + request.addEventListener('success', () => resolve(request.result)); + request.addEventListener('error', () => reject(request.error)); + }); + } + + function isPlainObject(v: any) { + const ctor = v?.constructor; + if (isFirefox) { + const constructorImpl = ctor?.toString(); + if (constructorImpl.startsWith('function Object() {') && constructorImpl.includes('[native code]')) + return true; + } + + return ctor === Object; + } + + function trySerialize(value: any): { trivial?: any, encoded?: any } { + let trivial = true; + const encoded = serializers.serializeAsCallArgument(value, v => { + const isTrivial = ( + isPlainObject(v) + || Array.isArray(v) + || typeof v === 'string' + || typeof v === 'number' + || typeof v === 'boolean' + || Object.is(v, null) + ); + + if (!isTrivial) + trivial = false; + + return { fallThrough: v }; + }); + if (trivial) + return { trivial: value }; + return { encoded }; + } + + const db = await idbRequestToPromise(indexedDB.open(dbInfo.name)); + const transaction = db.transaction(db.objectStoreNames, 'readonly'); + const stores = await Promise.all([...db.objectStoreNames].map(async storeName => { + const objectStore = transaction.objectStore(storeName); + + const keys = await idbRequestToPromise(objectStore.getAllKeys()); + const records = await Promise.all(keys.map(async key => { + const record: channels.IndexedDBDatabase['stores'][0]['records'][0] = {}; + + if (objectStore.keyPath === null) { + const { encoded, trivial } = trySerialize(key); + if (trivial) + record.key = trivial; + else + record.keyEncoded = encoded; + } + + const value = await idbRequestToPromise(objectStore.get(key)); + const { encoded, trivial } = trySerialize(value); + if (trivial) + record.value = trivial; + else + record.valueEncoded = encoded; + + return record; + })); + + const indexes = [...objectStore.indexNames].map(indexName => { + const index = objectStore.index(indexName); + return { + name: index.name, + keyPath: typeof index.keyPath === 'string' ? index.keyPath : undefined, + keyPathArray: Array.isArray(index.keyPath) ? index.keyPath : undefined, + multiEntry: index.multiEntry, + unique: index.unique, + }; + }); + + return { + name: storeName, + records: records, + indexes, + autoIncrement: objectStore.autoIncrement, + keyPath: typeof objectStore.keyPath === 'string' ? objectStore.keyPath : undefined, + keyPathArray: Array.isArray(objectStore.keyPath) ? objectStore.keyPath : undefined, + }; + })); + + return { + name: dbInfo.name, + version: dbInfo.version, + stores, + }; + } + + return { + localStorage: Object.keys(localStorage).map(name => ({ name, value: localStorage.getItem(name)! })), + indexedDB: recordIndexedDB ? await Promise.all((await indexedDB.databases()).map(collectDB)).catch(e => { + throw new Error('Unable to serialize IndexedDB: ' + e.message); + }) : undefined, + }; +} + +export async function restore(originState: channels.SetOriginStorage, serializers: ReturnType) { + for (const { name, value } of (originState.localStorage || [])) + localStorage.setItem(name, value); + + await Promise.all((originState.indexedDB ?? []).map(async dbInfo => { + const openRequest = indexedDB.open(dbInfo.name, dbInfo.version); + openRequest.addEventListener('upgradeneeded', () => { + const db = openRequest.result; + for (const store of dbInfo.stores) { + const objectStore = db.createObjectStore(store.name, { autoIncrement: store.autoIncrement, keyPath: store.keyPathArray ?? store.keyPath }); + for (const index of store.indexes) + objectStore.createIndex(index.name, index.keyPathArray ?? index.keyPath!, { unique: index.unique, multiEntry: index.multiEntry }); + } + }); + + function idbRequestToPromise(request: T) { + return new Promise((resolve, reject) => { + request.addEventListener('success', () => resolve(request.result)); + request.addEventListener('error', () => reject(request.error)); + }); + } + + // after `upgradeneeded` finishes, `success` event is fired. + const db = await idbRequestToPromise(openRequest); + const transaction = db.transaction(db.objectStoreNames, 'readwrite'); + await Promise.all(dbInfo.stores.map(async store => { + const objectStore = transaction.objectStore(store.name); + await Promise.all(store.records.map(async record => { + await idbRequestToPromise( + objectStore.add( + record.value ?? serializers.parseEvaluationResultValue(record.valueEncoded), + record.key ?? serializers.parseEvaluationResultValue(record.keyEncoded), + ) + ); + })); + })); + })).catch(e => { + throw new Error('Unable to restore IndexedDB: ' + e.message); + }); +} diff --git a/packages/playwright-core/src/common/timeoutSettings.ts b/packages/playwright-core/src/server/timeoutSettings.ts similarity index 97% rename from packages/playwright-core/src/common/timeoutSettings.ts rename to packages/playwright-core/src/server/timeoutSettings.ts index 65c8be1ecf265..1c71437e2a382 100644 --- a/packages/playwright-core/src/common/timeoutSettings.ts +++ b/packages/playwright-core/src/server/timeoutSettings.ts @@ -15,8 +15,9 @@ * limitations under the License. */ -import { debugMode } from '../utils'; +import { debugMode } from './utils/debug'; +// Keep in sync with client. export const DEFAULT_TIMEOUT = 30000; export const DEFAULT_LAUNCH_TIMEOUT = 3 * 60 * 1000; // 3 minutes diff --git a/packages/playwright-core/src/server/trace/recorder/DEPS.list b/packages/playwright-core/src/server/trace/recorder/DEPS.list index 201a4b001d0ee..195bdb5eb866b 100644 --- a/packages/playwright-core/src/server/trace/recorder/DEPS.list +++ b/packages/playwright-core/src/server/trace/recorder/DEPS.list @@ -1,10 +1,10 @@ [*] ../../ ../../har/ -../../../common/ ../../../protocol/ -../../../utils/ ../../../utilsBundle.ts +../../../utils/isomorphic/ ../../../zipBundle.ts ../../dispatchers/dispatcher.ts -../common/ \ No newline at end of file +../../utils +../common/ diff --git a/packages/playwright-core/src/server/trace/recorder/snapshotter.ts b/packages/playwright-core/src/server/trace/recorder/snapshotter.ts index 115cd3dd940d0..f4e288d077159 100644 --- a/packages/playwright-core/src/server/trace/recorder/snapshotter.ts +++ b/packages/playwright-core/src/server/trace/recorder/snapshotter.ts @@ -14,17 +14,19 @@ * limitations under the License. */ +import { frameSnapshotStreamer } from './snapshotterInjected'; +import { monotonicTime } from '../../../utils/isomorphic/time'; +import { calculateSha1, createGuid } from '../../utils/crypto'; +import { debugLogger } from '../../utils/debugLogger'; +import { eventsHelper } from '../../utils/eventsHelper'; +import { mime } from '../../../utilsBundle'; import { BrowserContext } from '../../browserContext'; import { Page } from '../../page'; -import type { RegisteredListener } from '../../../utils/eventsHelper'; -import { eventsHelper } from '../../../utils/eventsHelper'; -import { debugLogger } from '../../../utils/debugLogger'; -import type { Frame } from '../../frames'; + import type { SnapshotData } from './snapshotterInjected'; -import { frameSnapshotStreamer } from './snapshotterInjected'; -import { calculateSha1, createGuid, monotonicTime } from '../../../utils'; +import type { RegisteredListener } from '../../utils/eventsHelper'; +import type { Frame } from '../../frames'; import type { FrameSnapshot } from '@trace/snapshot'; -import { mime } from '../../../utilsBundle'; export type SnapshotterBlob = { buffer: Buffer, diff --git a/packages/playwright-core/src/server/trace/recorder/tracing.ts b/packages/playwright-core/src/server/trace/recorder/tracing.ts index c19c0a33d9918..fd9a724726061 100644 --- a/packages/playwright-core/src/server/trace/recorder/tracing.ts +++ b/packages/playwright-core/src/server/trace/recorder/tracing.ts @@ -17,28 +17,35 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; -import type { NameValue } from '../../../common/types'; -import type { TracingTracingStopChunkParams, StackFrame } from '@protocol/channels'; + +import { Snapshotter } from './snapshotter'; import { commandsWithTracingSnapshots } from '../../../protocol/debug'; -import { assert, createGuid, monotonicTime, SerializedFS, removeFolders, eventsHelper, type RegisteredListener } from '../../../utils'; +import { assert } from '../../../utils/isomorphic/assert'; +import { monotonicTime } from '../../../utils/isomorphic/time'; +import { eventsHelper } from '../../utils/eventsHelper'; +import { createGuid } from '../../utils/crypto'; import { Artifact } from '../../artifact'; import { BrowserContext } from '../../browserContext'; -import type { APIRequestContext } from '../../fetch'; -import type { CallMetadata, InstrumentationListener } from '../../instrumentation'; +import { Dispatcher } from '../../dispatchers/dispatcher'; +import { serializeError } from '../../errors'; +import { SerializedFS, removeFolders } from '../../utils/fileUtils'; +import { HarTracer } from '../../har/harTracer'; import { SdkObject } from '../../instrumentation'; import { Page } from '../../page'; -import type * as har from '@trace/har'; -import type { HarTracerDelegate } from '../../har/harTracer'; -import { HarTracer } from '../../har/harTracer'; -import type { FrameSnapshot } from '@trace/snapshot'; -import type * as trace from '@trace/trace'; + import type { SnapshotterBlob, SnapshotterDelegate } from './snapshotter'; -import { Snapshotter } from './snapshotter'; +import type { NameValue } from '../../../utils/isomorphic/types'; +import type { RegisteredListener } from '../../../utils'; import type { ConsoleMessage } from '../../console'; -import { Dispatcher } from '../../dispatchers/dispatcher'; -import { serializeError } from '../../errors'; import type { Dialog } from '../../dialog'; import type { Download } from '../../download'; +import type { APIRequestContext } from '../../fetch'; +import type { HarTracerDelegate } from '../../har/harTracer'; +import type { CallMetadata, InstrumentationListener } from '../../instrumentation'; +import type { StackFrame, TracingTracingStopChunkParams } from '@protocol/channels'; +import type * as har from '@trace/har'; +import type { FrameSnapshot } from '@trace/snapshot'; +import type * as trace from '@trace/trace'; const version: trace.VERSION = 7; @@ -103,7 +110,8 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps wallTime: 0, monotonicTime: 0, sdkLanguage: context.attribution.playwright.options.sdkLanguage, - testIdAttributeName + testIdAttributeName, + contextId: context.guid, }; if (context instanceof BrowserContext) { this._snapshotter = new Snapshotter(context, this); @@ -170,10 +178,16 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps this._state.recording = true; this._state.callIds.clear(); + // - Browser context network trace is shared across chunks as it contains resources + // used to serve page snapshots, so make a copy with the new name. + // - APIRequestContext network traces are chunk-specific, always start from scratch. + const preserveNetworkResources = this._context instanceof BrowserContext; if (options.name && options.name !== this._state.traceName) - this._changeTraceName(this._state, options.name); + this._changeTraceName(this._state, options.name, preserveNetworkResources); else this._allocateNewTraceFile(this._state); + if (!preserveNetworkResources) + this._fs.writeFile(this._state.networkFile, ''); this._fs.mkdir(path.dirname(this._state.traceFile)); const event: trace.TraceEvent = { @@ -267,14 +281,14 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps state.traceFile = path.join(state.tracesDir, `${state.traceName}${suffix}.trace`); } - private _changeTraceName(state: RecordingState, name: string) { + private _changeTraceName(state: RecordingState, name: string, preserveNetworkResources: boolean) { state.traceName = name; state.chunkOrdinal = 0; // Reset ordinal for the new name. this._allocateNewTraceFile(state); - // Network file survives across chunks, so make a copy with the new name. const newNetworkFile = path.join(state.tracesDir, name + '.network'); - this._fs.copyFile(state.networkFile, newNetworkFile); + if (preserveNetworkResources) + this._fs.copyFile(state.networkFile, newNetworkFile); state.networkFile = newNetworkFile; } diff --git a/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts b/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts index 8de07c2aad19e..36d4cf655eccf 100644 --- a/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts +++ b/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts @@ -14,17 +14,19 @@ * limitations under the License. */ -import type { BrowserContext } from '../../browserContext'; -import type { Page } from '../../page'; -import type { FrameSnapshot } from '@trace/snapshot'; -import type { SnapshotRenderer } from '../../../../../trace-viewer/src/sw/snapshotRenderer'; import { SnapshotStorage } from '../../../../../trace-viewer/src/sw/snapshotStorage'; -import type { SnapshotterBlob, SnapshotterDelegate } from '../recorder/snapshotter'; +import { ManualPromise } from '../../../utils'; +import { HarTracer } from '../../har/harTracer'; import { Snapshotter } from '../recorder/snapshotter'; + +import type { SnapshotRenderer } from '../../../../../trace-viewer/src/sw/snapshotRenderer'; +import type { BrowserContext } from '../../browserContext'; import type { HarTracerDelegate } from '../../har/harTracer'; -import { HarTracer } from '../../har/harTracer'; +import type { Page } from '../../page'; +import type { SnapshotterBlob, SnapshotterDelegate } from '../recorder/snapshotter'; import type * as har from '@trace/har'; -import { ManualPromise } from '../../../utils'; +import type { FrameSnapshot } from '@trace/snapshot'; + export class InMemorySnapshotter implements SnapshotterDelegate, HarTracerDelegate { private _blobs = new Map(); @@ -72,7 +74,7 @@ export class InMemorySnapshotter implements SnapshotterDelegate, HarTracerDelega } onEntryFinished(entry: har.Entry) { - this._storage.addResource(entry); + this._storage.addResource('', entry); } onContentBlob(sha1: string, buffer: Buffer) { @@ -85,7 +87,7 @@ export class InMemorySnapshotter implements SnapshotterDelegate, HarTracerDelega onFrameSnapshot(snapshot: FrameSnapshot): void { ++this._snapshotCount; - const renderer = this._storage.addFrameSnapshot(snapshot, []); + const renderer = this._storage.addFrameSnapshot('', snapshot, []); this._snapshotReadyPromises.get(snapshot.snapshotName || '')?.resolve(renderer); } diff --git a/packages/playwright-core/src/server/trace/viewer/DEPS.list b/packages/playwright-core/src/server/trace/viewer/DEPS.list index df8177e9518ec..cd0ac02b8a122 100644 --- a/packages/playwright-core/src/server/trace/viewer/DEPS.list +++ b/packages/playwright-core/src/server/trace/viewer/DEPS.list @@ -1,5 +1,6 @@ [*] ../../ +../../utils/ ../../registry/ ../../../generated/ ../../../utils/ diff --git a/packages/playwright-core/src/server/trace/viewer/traceViewer.ts b/packages/playwright-core/src/server/trace/viewer/traceViewer.ts index f852f6c996759..2b4d4d90f9ab2 100644 --- a/packages/playwright-core/src/server/trace/viewer/traceViewer.ts +++ b/packages/playwright-core/src/server/trace/viewer/traceViewer.ts @@ -14,19 +14,22 @@ * limitations under the License. */ -import path from 'path'; import fs from 'fs'; -import { HttpServer } from '../../../utils/httpServer'; -import type { Transport } from '../../../utils/httpServer'; -import { gracefullyProcessExitDoNotHang, isUnderTest } from '../../../utils'; -import { syncLocalStorageWithSettings } from '../../launchApp'; +import path from 'path'; + +import { gracefullyProcessExitDoNotHang } from '../../../utils'; +import { isUnderTest } from '../../../utils'; +import { HttpServer } from '../../utils/httpServer'; +import { open } from '../../../utilsBundle'; import { serverSideCallMetadata } from '../../instrumentation'; +import { syncLocalStorageWithSettings } from '../../launchApp'; +import { launchApp } from '../../launchApp'; import { createPlaywright } from '../../playwright'; import { ProgressController } from '../../progress'; -import { open } from '../../../utilsBundle'; -import type { Page } from '../../page'; + +import type { Transport } from '../../utils/httpServer'; import type { BrowserType } from '../../browserType'; -import { launchApp } from '../../launchApp'; +import type { Page } from '../../page'; export type TraceViewerServerOptions = { host?: string; @@ -67,6 +70,10 @@ export async function startTraceViewerServer(options?: TraceViewerServerOptions) server.routePrefix('/trace', (request, response) => { const url = new URL('http://localhost' + request.url!); const relativePath = url.pathname.slice('/trace'.length); + if (process.env.PW_HMR) { + // When running in Vite HMR mode, port is hardcoded in build.js + response.appendHeader('Access-Control-Allow-Origin', 'http://localhost:44223'); + } if (relativePath.endsWith('/stall.js')) return true; if (relativePath.startsWith('/file')) { @@ -135,6 +142,16 @@ export async function installRootRedirect(server: HttpServer, traceUrls: string[ server.routePath('/', (_, response) => { response.statusCode = 302; response.setHeader('Location', urlPath); + + if (process.env.EXPERIMENTAL_OPENAI_API_KEY) + response.appendHeader('Set-Cookie', `openai_api_key=${process.env.EXPERIMENTAL_OPENAI_API_KEY}`); + if (process.env.OPENAI_BASE_URL) + response.appendHeader('Set-Cookie', `openai_base_url=${process.env.OPENAI_BASE_URL}`); + if (process.env.EXPERIMENTAL_ANTHROPIC_API_KEY) + response.appendHeader('Set-Cookie', `anthropic_api_key=${process.env.EXPERIMENTAL_ANTHROPIC_API_KEY}`); + if (process.env.ANTHROPIC_BASE_URL) + response.appendHeader('Set-Cookie', `anthropic_base_url=${process.env.ANTHROPIC_BASE_URL}`); + response.end(); return true; }); diff --git a/packages/playwright-core/src/server/transport.ts b/packages/playwright-core/src/server/transport.ts index 507225b04c20f..ec2caec0c550e 100644 --- a/packages/playwright-core/src/server/transport.ts +++ b/packages/playwright-core/src/server/transport.ts @@ -15,13 +15,14 @@ * limitations under the License. */ +import { makeWaitForNextTask } from '../utils'; +import { httpHappyEyeballsAgent, httpsHappyEyeballsAgent } from './utils/happyEyeballs'; import { ws } from '../utilsBundle'; + import type { WebSocket } from '../utilsBundle'; -import type { ClientRequest, IncomingMessage } from 'http'; import type { Progress } from './progress'; -import { makeWaitForNextTask } from '../utils'; -import { httpHappyEyeballsAgent, httpsHappyEyeballsAgent } from '../utils/happy-eyeballs'; import type { HeadersArray } from './types'; +import type { ClientRequest, IncomingMessage } from 'http'; export const perMessageDeflate = { clientNoContextTakeover: true, diff --git a/packages/playwright-core/src/server/types.ts b/packages/playwright-core/src/server/types.ts index b58ea5af83bca..a8681fd6cf902 100644 --- a/packages/playwright-core/src/server/types.ts +++ b/packages/playwright-core/src/server/types.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import type { Size, Point, TimeoutOptions, HeadersArray } from '../common/types'; -export type { Size, Point, Rect, Quad, TimeoutOptions, HeadersArray } from '../common/types'; +import type { HeadersArray, Point, Size, TimeoutOptions } from '../utils/isomorphic/types'; +export type { HeadersArray, Point, Quad, Rect, Size, TimeoutOptions } from '../utils/isomorphic/types'; import type * as channels from '@protocol/channels'; export type StrictOptions = { @@ -84,6 +84,8 @@ export type ReducedMotion = 'no-preference' | 'reduce' | 'no-override'; export type ForcedColors = 'active' | 'none' | 'no-override'; +export type Contrast = 'no-preference' | 'more' | 'no-override'; + export type DeviceDescriptor = { userAgent: string, viewport: Size, diff --git a/packages/playwright-core/src/server/utils/DEPS.list b/packages/playwright-core/src/server/utils/DEPS.list new file mode 100644 index 0000000000000..8d1b7a30f27b9 --- /dev/null +++ b/packages/playwright-core/src/server/utils/DEPS.list @@ -0,0 +1,9 @@ +[*] +../../utils +../../utils/isomorphic +../../utilsBundle.ts +../../zipBundle.ts + +[comparators.ts] +./image_tools +../../third_party/pixelmatch diff --git a/packages/playwright-core/src/utils/ascii.ts b/packages/playwright-core/src/server/utils/ascii.ts similarity index 100% rename from packages/playwright-core/src/utils/ascii.ts rename to packages/playwright-core/src/server/utils/ascii.ts diff --git a/packages/playwright-core/src/utils/comparators.ts b/packages/playwright-core/src/server/utils/comparators.ts similarity index 96% rename from packages/playwright-core/src/utils/comparators.ts rename to packages/playwright-core/src/server/utils/comparators.ts index c848200d6689d..06b6bdc6ff8f4 100644 --- a/packages/playwright-core/src/utils/comparators.ts +++ b/packages/playwright-core/src/server/utils/comparators.ts @@ -15,12 +15,12 @@ * limitations under the License. */ -import { colors, jpegjs } from '../utilsBundle'; +import { compare } from './image_tools/compare'; // @ts-ignore -import pixelmatch from '../third_party/pixelmatch'; -import { compare } from '../image_tools/compare'; -import { diff } from '../utilsBundle'; -import { PNG } from '../utilsBundle'; +import pixelmatch from '../../third_party/pixelmatch'; +import { jpegjs } from '../../utilsBundle'; +import { colors, diff } from '../../utilsBundle'; +import { PNG } from '../../utilsBundle'; export type ImageComparatorOptions = { threshold?: number, maxDiffPixels?: number, maxDiffPixelRatio?: number, comparator?: string }; export type ComparatorResult = { diff?: Buffer; errorMessage: string; } | null; diff --git a/packages/playwright-core/src/utils/crypto.ts b/packages/playwright-core/src/server/utils/crypto.ts similarity index 99% rename from packages/playwright-core/src/utils/crypto.ts rename to packages/playwright-core/src/server/utils/crypto.ts index f538912d24bd9..ab51dbb25a3c6 100644 --- a/packages/playwright-core/src/utils/crypto.ts +++ b/packages/playwright-core/src/server/utils/crypto.ts @@ -15,7 +15,8 @@ */ import crypto from 'crypto'; -import { assert } from './debug'; + +import { assert } from '../../utils/isomorphic/assert'; export function createGuid(): string { return crypto.randomBytes(16).toString('hex'); diff --git a/packages/playwright-core/src/utils/debug.ts b/packages/playwright-core/src/server/utils/debug.ts similarity index 66% rename from packages/playwright-core/src/utils/debug.ts rename to packages/playwright-core/src/server/utils/debug.ts index 2e199b3a31360..489c772b70fc7 100644 --- a/packages/playwright-core/src/utils/debug.ts +++ b/packages/playwright-core/src/server/utils/debug.ts @@ -16,23 +16,14 @@ import { getFromENV } from './env'; -export function assert(value: any, message?: string): asserts value { - if (!value) - throw new Error(message || 'Assertion error'); -} - -export function debugAssert(value: any, message?: string): asserts value { - if (isUnderTest() && !value) - throw new Error(message); -} +const _debugMode = getFromENV('PWDEBUG') || ''; -const debugEnv = getFromENV('PWDEBUG') || ''; export function debugMode() { - if (debugEnv === 'console') + if (_debugMode === 'console') return 'console'; - if (debugEnv === '0' || debugEnv === 'false') + if (_debugMode === '0' || _debugMode === 'false') return ''; - return debugEnv ? 'inspector' : ''; + return _debugMode ? 'inspector' : ''; } let _isUnderTest = !!process.env.PWTEST_UNDER_TEST; diff --git a/packages/playwright-core/src/utils/debugLogger.ts b/packages/playwright-core/src/server/utils/debugLogger.ts similarity index 98% rename from packages/playwright-core/src/utils/debugLogger.ts rename to packages/playwright-core/src/server/utils/debugLogger.ts index d50180a2ed360..84a0f53d82cbb 100644 --- a/packages/playwright-core/src/utils/debugLogger.ts +++ b/packages/playwright-core/src/server/utils/debugLogger.ts @@ -14,9 +14,10 @@ * limitations under the License. */ -import { debug } from '../utilsBundle'; import fs from 'fs'; +import { debug } from '../../utilsBundle'; + const debugLoggerColorMap = { 'api': 45, // cyan 'protocol': 34, // green diff --git a/packages/playwright-core/src/utils/env.ts b/packages/playwright-core/src/server/utils/env.ts similarity index 93% rename from packages/playwright-core/src/utils/env.ts rename to packages/playwright-core/src/server/utils/env.ts index 2a4dd0bfd4f33..500c180f56745 100644 --- a/packages/playwright-core/src/utils/env.ts +++ b/packages/playwright-core/src/server/utils/env.ts @@ -47,3 +47,7 @@ export function getPackageManagerExecCommand() { return 'pnpm exec'; return 'npx'; } + +export function isLikelyNpxGlobal() { + return process.argv.length >= 2 && process.argv[1].includes('_npx'); +} diff --git a/packages/playwright-core/src/utils/eventsHelper.ts b/packages/playwright-core/src/server/utils/eventsHelper.ts similarity index 100% rename from packages/playwright-core/src/utils/eventsHelper.ts rename to packages/playwright-core/src/server/utils/eventsHelper.ts diff --git a/packages/playwright-core/src/utils/expectUtils.ts b/packages/playwright-core/src/server/utils/expectUtils.ts similarity index 94% rename from packages/playwright-core/src/utils/expectUtils.ts rename to packages/playwright-core/src/server/utils/expectUtils.ts index 0ae21e860270b..6d7a2a1e3db2f 100644 --- a/packages/playwright-core/src/utils/expectUtils.ts +++ b/packages/playwright-core/src/server/utils/expectUtils.ts @@ -14,8 +14,9 @@ * limitations under the License. */ +import { isRegExp, isString } from '../../utils/isomorphic/rtti'; + import type { ExpectedTextValue } from '@protocol/channels'; -import { isRegExp, isString } from './rtti'; export function serializeExpectedTextValues(items: (string | RegExp)[], options: { matchSubstring?: boolean, normalizeWhiteSpace?: boolean, ignoreCase?: boolean } = {}): ExpectedTextValue[] { return items.map(i => ({ diff --git a/packages/playwright-core/src/utils/fileUtils.ts b/packages/playwright-core/src/server/utils/fileUtils.ts similarity index 97% rename from packages/playwright-core/src/utils/fileUtils.ts rename to packages/playwright-core/src/server/utils/fileUtils.ts index b7f441aa37748..4179df79fe1c3 100644 --- a/packages/playwright-core/src/utils/fileUtils.ts +++ b/packages/playwright-core/src/server/utils/fileUtils.ts @@ -16,11 +16,11 @@ import fs from 'fs'; import path from 'path'; -import { ManualPromise } from './manualPromise'; -import type { EventEmitter } from 'events'; -import { yazl } from '../zipBundle'; -export const fileUploadSizeLimit = 50 * 1024 * 1024; +import { ManualPromise } from '../../utils/isomorphic/manualPromise'; +import { yazl } from '../../zipBundle'; + +import type { EventEmitter } from 'events'; export const existsAsync = (path: string): Promise => new Promise(resolve => fs.stat(path, err => resolve(!err))); diff --git a/packages/playwright-core/src/utils/happy-eyeballs.ts b/packages/playwright-core/src/server/utils/happyEyeballs.ts similarity index 95% rename from packages/playwright-core/src/utils/happy-eyeballs.ts rename to packages/playwright-core/src/server/utils/happyEyeballs.ts index 02b78de4f045e..eb8531db4c1a4 100644 --- a/packages/playwright-core/src/utils/happy-eyeballs.ts +++ b/packages/playwright-core/src/server/utils/happyEyeballs.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import * as dns from 'dns'; -import * as http from 'http'; -import * as https from 'https'; -import * as net from 'net'; -import * as tls from 'tls'; -import { ManualPromise } from './manualPromise'; -import { assert } from './debug'; -import { monotonicTime } from './time'; +import dns from 'dns'; +import http from 'http'; +import https from 'https'; +import net from 'net'; +import tls from 'tls'; + +import { assert } from '../../utils/isomorphic/assert'; +import { ManualPromise } from '../../utils/isomorphic/manualPromise'; +import { monotonicTime } from '../../utils/isomorphic/time'; // Implementation(partial) of Happy Eyeballs 2 algorithm described in // https://www.rfc-editor.org/rfc/rfc8305 diff --git a/packages/playwright-core/src/utils/hostPlatform.ts b/packages/playwright-core/src/server/utils/hostPlatform.ts similarity index 99% rename from packages/playwright-core/src/utils/hostPlatform.ts rename to packages/playwright-core/src/server/utils/hostPlatform.ts index 0563e4ab29da4..11ab5af60f3e5 100644 --- a/packages/playwright-core/src/utils/hostPlatform.ts +++ b/packages/playwright-core/src/server/utils/hostPlatform.ts @@ -15,6 +15,7 @@ */ import os from 'os'; + import { getLinuxDistributionInfoSync } from './linuxUtils'; export type HostPlatform = 'win64' | diff --git a/packages/playwright-core/src/utils/httpServer.ts b/packages/playwright-core/src/server/utils/httpServer.ts similarity index 94% rename from packages/playwright-core/src/utils/httpServer.ts rename to packages/playwright-core/src/server/utils/httpServer.ts index 8da2a0e0d0b0e..0fd977f3c043e 100644 --- a/packages/playwright-core/src/utils/httpServer.ts +++ b/packages/playwright-core/src/server/utils/httpServer.ts @@ -14,14 +14,16 @@ * limitations under the License. */ -import type http from 'http'; import fs from 'fs'; import path from 'path'; -import { mime, wsServer } from '../utilsBundle'; -import { assert } from './debug'; -import { createHttpServer } from './network'; -import { ManualPromise } from './manualPromise'; + +import { mime, wsServer } from '../../utilsBundle'; import { createGuid } from './crypto'; +import { assert } from '../../utils/isomorphic/assert'; +import { ManualPromise } from '../../utils/isomorphic/manualPromise'; +import { createHttpServer } from './network'; + +import type http from 'http'; export type ServerRouteHandler = (request: http.IncomingMessage, response: http.ServerResponse) => boolean; @@ -214,12 +216,6 @@ export class HttpServer { } private _onRequest(request: http.IncomingMessage, response: http.ServerResponse) { - response.setHeader('Access-Control-Allow-Origin', '*'); - response.setHeader('Access-Control-Request-Method', '*'); - response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET'); - if (request.headers.origin) - response.setHeader('Access-Control-Allow-Headers', request.headers.origin); - if (request.method === 'OPTIONS') { response.writeHead(200); response.end(); diff --git a/packages/playwright-core/src/image_tools/colorUtils.ts b/packages/playwright-core/src/server/utils/image_tools/colorUtils.ts similarity index 100% rename from packages/playwright-core/src/image_tools/colorUtils.ts rename to packages/playwright-core/src/server/utils/image_tools/colorUtils.ts diff --git a/packages/playwright-core/src/image_tools/compare.ts b/packages/playwright-core/src/server/utils/image_tools/compare.ts similarity index 99% rename from packages/playwright-core/src/image_tools/compare.ts rename to packages/playwright-core/src/server/utils/image_tools/compare.ts index ee4b6b691d07f..8dddb5df35d88 100644 --- a/packages/playwright-core/src/image_tools/compare.ts +++ b/packages/playwright-core/src/server/utils/image_tools/compare.ts @@ -16,7 +16,7 @@ import { blendWithWhite, colorDeltaE94, rgb2gray } from './colorUtils'; import { ImageChannel } from './imageChannel'; -import { ssim, FastStats } from './stats'; +import { FastStats, ssim } from './stats'; const SSIM_WINDOW_RADIUS = 15; const VARIANCE_WINDOW_RADIUS = 1; diff --git a/packages/playwright-core/src/image_tools/imageChannel.ts b/packages/playwright-core/src/server/utils/image_tools/imageChannel.ts similarity index 100% rename from packages/playwright-core/src/image_tools/imageChannel.ts rename to packages/playwright-core/src/server/utils/image_tools/imageChannel.ts diff --git a/packages/playwright-core/src/image_tools/stats.ts b/packages/playwright-core/src/server/utils/image_tools/stats.ts similarity index 100% rename from packages/playwright-core/src/image_tools/stats.ts rename to packages/playwright-core/src/server/utils/image_tools/stats.ts diff --git a/packages/playwright-core/src/utils/linuxUtils.ts b/packages/playwright-core/src/server/utils/linuxUtils.ts similarity index 72% rename from packages/playwright-core/src/utils/linuxUtils.ts rename to packages/playwright-core/src/server/utils/linuxUtils.ts index 5d98c823a50f9..86d6362588694 100644 --- a/packages/playwright-core/src/utils/linuxUtils.ts +++ b/packages/playwright-core/src/server/utils/linuxUtils.ts @@ -23,26 +23,6 @@ let osRelease: { version: string, } | undefined; -export async function getLinuxDistributionInfo(): Promise<{ id: string, version: string } | undefined> { - if (process.platform !== 'linux') - return undefined; - if (!osRelease && !didFailToReadOSRelease) { - try { - // List of /etc/os-release values for different distributions could be - // found here: https://gist.github.com/aslushnikov/8ceddb8288e4cf9db3039c02e0f4fb75 - const osReleaseText = await fs.promises.readFile('/etc/os-release', 'utf8'); - const fields = parseOSReleaseText(osReleaseText); - osRelease = { - id: fields.get('id') ?? '', - version: fields.get('version_id') ?? '', - }; - } catch (e) { - didFailToReadOSRelease = true; - } - } - return osRelease; -} - export function getLinuxDistributionInfoSync(): { id: string, version: string } | undefined { if (process.platform !== 'linux') return undefined; diff --git a/packages/playwright-core/src/utils/network.ts b/packages/playwright-core/src/server/utils/network.ts similarity index 97% rename from packages/playwright-core/src/utils/network.ts rename to packages/playwright-core/src/server/utils/network.ts index 25d3a111563af..8e0357f958122 100644 --- a/packages/playwright-core/src/utils/network.ts +++ b/packages/playwright-core/src/server/utils/network.ts @@ -16,13 +16,14 @@ import http from 'http'; -import https from 'https'; import http2 from 'http2'; -import type net from 'net'; -import { getProxyForUrl } from '../utilsBundle'; -import { HttpsProxyAgent } from '../utilsBundle'; +import https from 'https'; import url from 'url'; -import { httpHappyEyeballsAgent, httpsHappyEyeballsAgent } from './happy-eyeballs'; + +import { HttpsProxyAgent, getProxyForUrl } from '../../utilsBundle'; +import { httpHappyEyeballsAgent, httpsHappyEyeballsAgent } from './happyEyeballs'; + +import type net from 'net'; export type HTTPRequestParams = { url: string, @@ -50,7 +51,7 @@ export function httpRequest(params: HTTPRequestParams, onResponse: (r: http.Inco const proxyURL = getProxyForUrl(params.url); if (proxyURL) { - const parsedProxyURL = new URL(proxyURL); + const parsedProxyURL = url.parse(proxyURL); if (params.url.startsWith('http:')) { options = { path: parsedUrl.href, diff --git a/packages/playwright-core/src/server/utils/nodePlatform.ts b/packages/playwright-core/src/server/utils/nodePlatform.ts new file mode 100644 index 0000000000000..20944ae3f45e8 --- /dev/null +++ b/packages/playwright-core/src/server/utils/nodePlatform.ts @@ -0,0 +1,173 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import crypto from 'crypto'; +import fs from 'fs'; +import path from 'path'; +import * as util from 'util'; +import { Readable, Writable, pipeline } from 'stream'; +import { EventEmitter } from 'events'; + +import { colors } from '../../utilsBundle'; +import { debugLogger } from './debugLogger'; +import { currentZone, emptyZone } from './zones'; +import { debugMode, isUnderTest } from './debug'; + +import type { Platform, Zone } from '../../client/platform'; +import type { Zone as ZoneImpl } from './zones'; +import type * as channels from '@protocol/channels'; + +const pipelineAsync = util.promisify(pipeline); + +class NodeZone implements Zone { + private _zone: ZoneImpl; + + constructor(zone: ZoneImpl) { + this._zone = zone; + } + + push(data: T) { + return new NodeZone(this._zone.with('apiZone', data)); + } + + pop() { + return new NodeZone(this._zone.without('apiZone')); + } + + run(func: () => R): R { + return this._zone.run(func); + } + + data(): T | undefined { + return this._zone.data('apiZone'); + } +} + +let boxedStackPrefixes: string[] = []; +export function setBoxedStackPrefixes(prefixes: string[]) { + boxedStackPrefixes = prefixes; +} + +const coreDir = path.dirname(require.resolve('../../../package.json')); + +export const nodePlatform: Platform = { + name: 'node', + + boxedStackPrefixes: () => { + if (process.env.PWDEBUGIMPL) + return []; + return [coreDir, ...boxedStackPrefixes]; + }, + + calculateSha1: (text: string) => { + const sha1 = crypto.createHash('sha1'); + sha1.update(text); + return Promise.resolve(sha1.digest('hex')); + }, + + colors, + + coreDir, + + createGuid: () => crypto.randomBytes(16).toString('hex'), + + defaultMaxListeners: () => EventEmitter.defaultMaxListeners, + fs: () => fs, + + env: process.env, + + inspectCustom: util.inspect.custom, + + isDebugMode: () => !!debugMode(), + + isJSDebuggerAttached: () => !!require('inspector').url(), + + isLogEnabled(name: 'api' | 'channel') { + return debugLogger.isEnabled(name); + }, + + isUnderTest: () => isUnderTest(), + + log(name: 'api' | 'channel', message: string | Error | object) { + debugLogger.log(name, message); + }, + + path: () => path, + + pathSeparator: path.sep, + + showInternalStackFrames: () => !!process.env.PWDEBUGIMPL, + + async streamFile(path: string, stream: Writable): Promise { + await pipelineAsync(fs.createReadStream(path), stream); + }, + + streamReadable: (channel: channels.StreamChannel) => { + return new ReadableStreamImpl(channel); + }, + + streamWritable: (channel: channels.WritableStreamChannel) => { + return new WritableStreamImpl(channel); + }, + + zones: { + current: () => new NodeZone(currentZone()), + empty: new NodeZone(emptyZone), + } +}; + +class ReadableStreamImpl extends Readable { + private _channel: channels.StreamChannel; + + constructor(channel: channels.StreamChannel) { + super(); + this._channel = channel; + } + + override async _read() { + const result = await this._channel.read({ size: 1024 * 1024 }); + if (result.binary.byteLength) + this.push(result.binary); + else + this.push(null); + } + + override _destroy(error: Error | null, callback: (error: Error | null | undefined) => void): void { + // Stream might be destroyed after the connection was closed. + this._channel.close().catch(e => null); + super._destroy(error, callback); + } +} + +class WritableStreamImpl extends Writable { + private _channel: channels.WritableStreamChannel; + + constructor(channel: channels.WritableStreamChannel) { + super(); + this._channel = channel; + } + + override async _write(chunk: Buffer | string, encoding: BufferEncoding, callback: (error?: Error | null) => void) { + const error = await this._channel.write({ binary: typeof chunk === 'string' ? Buffer.from(chunk) : chunk }).catch(e => e); + callback(error || null); + } + + override async _final(callback: (error?: Error | null) => void) { + // Stream might be destroyed after the connection was closed. + const error = await this._channel.close().catch(e => e); + callback(error || null); + } +} diff --git a/packages/playwright-core/src/protocol/transport.ts b/packages/playwright-core/src/server/utils/pipeTransport.ts similarity index 95% rename from packages/playwright-core/src/protocol/transport.ts rename to packages/playwright-core/src/server/utils/pipeTransport.ts index e647100c63a0b..64b1d80e8fcb8 100644 --- a/packages/playwright-core/src/protocol/transport.ts +++ b/packages/playwright-core/src/server/utils/pipeTransport.ts @@ -14,18 +14,18 @@ * limitations under the License. */ -import { makeWaitForNextTask } from '../utils'; +import { makeWaitForNextTask } from './task'; -export interface WritableStream { +interface WritableStream { write(data: Buffer): void; } -export interface ReadableStream { +interface ReadableStream { on(event: 'data', callback: (b: Buffer) => void): void; on(event: 'close', callback: () => void): void; } -export interface ClosableStream { +interface ClosableStream { close(): void; } diff --git a/packages/playwright-core/src/utils/processLauncher.ts b/packages/playwright-core/src/server/utils/processLauncher.ts similarity index 99% rename from packages/playwright-core/src/utils/processLauncher.ts rename to packages/playwright-core/src/server/utils/processLauncher.ts index 1310f952771f9..90bc1507fc74a 100644 --- a/packages/playwright-core/src/utils/processLauncher.ts +++ b/packages/playwright-core/src/server/utils/processLauncher.ts @@ -15,11 +15,12 @@ * limitations under the License. */ -import fs from 'fs'; import * as childProcess from 'child_process'; +import fs from 'fs'; import * as readline from 'readline'; -import { isUnderTest } from './'; + import { removeFolders } from './fileUtils'; +import { isUnderTest } from '../../utils'; export type Env = {[key: string]: string | number | boolean | undefined}; diff --git a/packages/playwright-core/src/utils/profiler.ts b/packages/playwright-core/src/server/utils/profiler.ts similarity index 96% rename from packages/playwright-core/src/utils/profiler.ts rename to packages/playwright-core/src/server/utils/profiler.ts index b68d96040449d..e414f0ff4a960 100644 --- a/packages/playwright-core/src/utils/profiler.ts +++ b/packages/playwright-core/src/server/utils/profiler.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import * as fs from 'fs'; -import * as path from 'path'; +import fs from 'fs'; +import path from 'path'; const profileDir = process.env.PWTEST_PROFILE_DIR || ''; diff --git a/packages/playwright-core/src/common/socksProxy.ts b/packages/playwright-core/src/server/utils/socksProxy.ts similarity index 98% rename from packages/playwright-core/src/common/socksProxy.ts rename to packages/playwright-core/src/server/utils/socksProxy.ts index 6566262d643d8..40c62c43c3327 100644 --- a/packages/playwright-core/src/common/socksProxy.ts +++ b/packages/playwright-core/src/server/utils/socksProxy.ts @@ -15,11 +15,14 @@ */ import EventEmitter from 'events'; -import type { AddressInfo } from 'net'; import net from 'net'; -import { debugLogger } from '../utils/debugLogger'; -import { createSocket } from '../utils/happy-eyeballs'; -import { assert, createGuid, } from '../utils'; + +import { assert } from '../../utils/isomorphic/assert'; +import { createGuid } from './crypto'; +import { debugLogger } from './debugLogger'; +import { createSocket } from './happyEyeballs'; + +import type { AddressInfo } from 'net'; // https://tools.ietf.org/html/rfc1928 diff --git a/packages/playwright-core/src/utils/spawnAsync.ts b/packages/playwright-core/src/server/utils/spawnAsync.ts similarity index 99% rename from packages/playwright-core/src/utils/spawnAsync.ts rename to packages/playwright-core/src/server/utils/spawnAsync.ts index 8e286fad47b90..f68719d6200bf 100644 --- a/packages/playwright-core/src/utils/spawnAsync.ts +++ b/packages/playwright-core/src/server/utils/spawnAsync.ts @@ -14,9 +14,10 @@ * limitations under the License. */ -import type { SpawnOptions } from 'child_process'; import { spawn } from 'child_process'; +import type { SpawnOptions } from 'child_process'; + export function spawnAsync(cmd: string, args: string[], options: SpawnOptions = {}): Promise<{stdout: string, stderr: string, code: number | null, error?: Error}> { const process = spawn(cmd, args, Object.assign({ windowsHide: true }, options)); diff --git a/packages/playwright-core/src/utils/task.ts b/packages/playwright-core/src/server/utils/task.ts similarity index 100% rename from packages/playwright-core/src/utils/task.ts rename to packages/playwright-core/src/server/utils/task.ts diff --git a/packages/playwright-core/src/utils/userAgent.ts b/packages/playwright-core/src/server/utils/userAgent.ts similarity index 77% rename from packages/playwright-core/src/utils/userAgent.ts rename to packages/playwright-core/src/server/utils/userAgent.ts index 17b1bc51c87c7..d9c7619ac51f7 100644 --- a/packages/playwright-core/src/utils/userAgent.ts +++ b/packages/playwright-core/src/server/utils/userAgent.ts @@ -16,8 +16,8 @@ import { execSync } from 'child_process'; import os from 'os'; + import { getLinuxDistributionInfoSync } from '../utils/linuxUtils'; -import { wrapInASCIIBox } from './ascii'; let cachedUserAgent: string | undefined; @@ -77,31 +77,6 @@ export function getEmbedderName(): { embedderName: string, embedderVersion: stri } export function getPlaywrightVersion(majorMinorOnly = false): string { - const version = process.env.PW_VERSION_OVERRIDE || require('./../../package.json').version; + const version = process.env.PW_VERSION_OVERRIDE || require('./../../../package.json').version; return majorMinorOnly ? version.split('.').slice(0, 2).join('.') : version; } - -export function userAgentVersionMatchesErrorMessage(userAgent: string) { - const match = userAgent.match(/^Playwright\/(\d+\.\d+\.\d+)/); - if (!match) { - // Cannot parse user agent - be lax. - return; - } - const received = match[1].split('.').slice(0, 2).join('.'); - const expected = getPlaywrightVersion(true); - if (received !== expected) { - return wrapInASCIIBox([ - `Playwright version mismatch:`, - ` - server version: v${expected}`, - ` - client version: v${received}`, - ``, - `If you are using VSCode extension, restart VSCode.`, - ``, - `If you are connecting to a remote service,`, - `keep your local Playwright version in sync`, - `with the remote service version.`, - ``, - `<3 Playwright Team` - ].join('\n'), 1); - } -} diff --git a/packages/playwright-core/src/utils/wsServer.ts b/packages/playwright-core/src/server/utils/wsServer.ts similarity index 96% rename from packages/playwright-core/src/utils/wsServer.ts rename to packages/playwright-core/src/server/utils/wsServer.ts index 636a57c3cc85a..68362f14de280 100644 --- a/packages/playwright-core/src/utils/wsServer.ts +++ b/packages/playwright-core/src/server/utils/wsServer.ts @@ -14,12 +14,14 @@ * limitations under the License. */ +import { createHttpServer } from './network'; +import { wsServer } from '../../utilsBundle'; +import { debugLogger } from './debugLogger'; + +import type { WebSocket, WebSocketServer } from '../../utilsBundle'; import type http from 'http'; import type stream from 'stream'; -import { createHttpServer } from '../utils'; -import type { WebSocketServer, WebSocket } from '../utilsBundle'; -import { wsServer } from '../utilsBundle'; -import { debugLogger } from './debugLogger'; + let lastConnectionId = 0; const kConnectionSymbol = Symbol('kConnection'); diff --git a/packages/playwright-core/src/utils/zipFile.ts b/packages/playwright-core/src/server/utils/zipFile.ts similarity index 95% rename from packages/playwright-core/src/utils/zipFile.ts rename to packages/playwright-core/src/server/utils/zipFile.ts index 3ae68b16503e9..43b5a3430c7d1 100644 --- a/packages/playwright-core/src/utils/zipFile.ts +++ b/packages/playwright-core/src/server/utils/zipFile.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -import { yauzl } from '../zipBundle'; -import type { UnzipFile, Entry } from '../zipBundle'; +import { yauzl } from '../../zipBundle'; + +import type { Entry, UnzipFile } from '../../zipBundle'; export class ZipFile { private _fileName: string; diff --git a/packages/playwright-core/src/utils/zones.ts b/packages/playwright-core/src/server/utils/zones.ts similarity index 63% rename from packages/playwright-core/src/utils/zones.ts rename to packages/playwright-core/src/server/utils/zones.ts index 32664c3898fa4..b5860167b0696 100644 --- a/packages/playwright-core/src/utils/zones.ts +++ b/packages/playwright-core/src/server/utils/zones.ts @@ -18,36 +18,13 @@ import { AsyncLocalStorage } from 'async_hooks'; export type ZoneType = 'apiZone' | 'stepZone'; -class ZoneManager { - private readonly _asyncLocalStorage = new AsyncLocalStorage(); - private readonly _emptyZone = Zone.createEmpty(this._asyncLocalStorage); - - run(type: ZoneType, data: T, func: () => R): R { - return this.current().with(type, data).run(func); - } - - zoneData(type: ZoneType): T | undefined { - return this.current().data(type); - } - - current(): Zone { - return this._asyncLocalStorage.getStore() ?? this._emptyZone; - } - - empty(): Zone { - return this._emptyZone; - } -} +const asyncLocalStorage = new AsyncLocalStorage(); export class Zone { private readonly _asyncLocalStorage: AsyncLocalStorage; private readonly _data: ReadonlyMap; - static createEmpty(asyncLocalStorage: AsyncLocalStorage) { - return new Zone(asyncLocalStorage, new Map()); - } - - private constructor(asyncLocalStorage: AsyncLocalStorage, store: Map) { + constructor(asyncLocalStorage: AsyncLocalStorage, store: Map) { this._asyncLocalStorage = asyncLocalStorage; this._data = store; } @@ -71,4 +48,8 @@ export class Zone { } } -export const zones = new ZoneManager(); +export const emptyZone = new Zone(asyncLocalStorage, new Map()); + +export function currentZone(): Zone { + return asyncLocalStorage.getStore() ?? emptyZone; +} diff --git a/packages/playwright-core/src/server/webkit/protocol.d.ts b/packages/playwright-core/src/server/webkit/protocol.d.ts index 9abd47bcfd779..c915b74e116a7 100644 --- a/packages/playwright-core/src/server/webkit/protocol.d.ts +++ b/packages/playwright-core/src/server/webkit/protocol.d.ts @@ -193,142 +193,6 @@ export module Protocol { } } - export module ApplicationCache { - /** - * Detailed application cache resource information. - */ - export interface ApplicationCacheResource { - /** - * Resource url. - */ - url: string; - /** - * Resource size. - */ - size: number; - /** - * Resource type. - */ - type: string; - } - /** - * Detailed application cache information. - */ - export interface ApplicationCache { - /** - * Manifest URL. - */ - manifestURL: string; - /** - * Application cache size. - */ - size: number; - /** - * Application cache creation time. - */ - creationTime: number; - /** - * Application cache update time. - */ - updateTime: number; - /** - * Application cache resources. - */ - resources: ApplicationCacheResource[]; - } - /** - * Frame identifier - manifest URL pair. - */ - export interface FrameWithManifest { - /** - * Frame identifier. - */ - frameId: Network.FrameId; - /** - * Manifest URL. - */ - manifestURL: string; - /** - * Application cache status. - */ - status: number; - } - - export type applicationCacheStatusUpdatedPayload = { - /** - * Identifier of the frame containing document whose application cache updated status. - */ - frameId: Network.FrameId; - /** - * Manifest URL. - */ - manifestURL: string; - /** - * Updated application cache status. - */ - status: number; - } - export type networkStateUpdatedPayload = { - isNowOnline: boolean; - } - - /** - * Returns array of frame identifiers with manifest urls for each frame containing a document associated with some application cache. - */ - export type getFramesWithManifestsParameters = { - } - export type getFramesWithManifestsReturnValue = { - /** - * Array of frame identifiers with manifest urls for each frame containing a document associated with some application cache. - */ - frameIds: FrameWithManifest[]; - } - /** - * Enables application cache domain notifications. - */ - export type enableParameters = { - } - export type enableReturnValue = { - } - /** - * Disable application cache domain notifications. - */ - export type disableParameters = { - } - export type disableReturnValue = { - } - /** - * Returns manifest URL for document in the given frame. - */ - export type getManifestForFrameParameters = { - /** - * Identifier of the frame containing document whose manifest is retrieved. - */ - frameId: Network.FrameId; - } - export type getManifestForFrameReturnValue = { - /** - * Manifest URL for document in the given frame. - */ - manifestURL: string; - } - /** - * Returns relevant application cache data for the document in given frame. - */ - export type getApplicationCacheForFrameParameters = { - /** - * Identifier of the frame containing document whose application cache is retrieved. - */ - frameId: Network.FrameId; - } - export type getApplicationCacheForFrameReturnValue = { - /** - * Relevant application cache data for the document in given frame. - */ - applicationCache: ApplicationCache; - } - } - export module Audit { @@ -3644,81 +3508,6 @@ might return multiple quads for inline nodes. } } - export module Database { - /** - * Unique identifier of Database object. - */ - export type DatabaseId = string; - /** - * Database object. - */ - export interface Database { - /** - * Database ID. - */ - id: DatabaseId; - /** - * Database domain. - */ - domain: string; - /** - * Database name. - */ - name: string; - /** - * Database version. - */ - version: string; - } - /** - * Database error. - */ - export interface Error { - /** - * Error message. - */ - message: string; - /** - * Error code. - */ - code: number; - } - - export type addDatabasePayload = { - database: Database; - } - - /** - * Enables database tracking, database events will now be delivered to the client. - */ - export type enableParameters = { - } - export type enableReturnValue = { - } - /** - * Disables database tracking, prevents database events from being sent to the client. - */ - export type disableParameters = { - } - export type disableReturnValue = { - } - export type getDatabaseTableNamesParameters = { - databaseId: DatabaseId; - } - export type getDatabaseTableNamesReturnValue = { - tableNames: string[]; - } - export type executeSQLParameters = { - databaseId: DatabaseId; - query: string; - } - export type executeSQLReturnValue = { - columnNames?: string[]; - values?: any[]; - sqlError?: Error; - } - } - /** * Debugger domain exposes JavaScript debugging capabilities. It allows setting and removing breakpoints, stepping through execution, exploring stack traces, etc. */ @@ -7781,6 +7570,18 @@ the top of the viewport and Y increases as it proceeds towards the bottom of the } export type setIgnoreCertificateErrorsReturnValue = { } + /** + * Changes page zoom factor. + */ + export type setPageZoomFactorParameters = { + /** + * Unique identifier of the page proxy. + */ + pageProxyId: PageProxyID; + zoomFactor: number; + } + export type setPageZoomFactorReturnValue = { + } /** * Returns all cookies in the given browser context. */ @@ -9273,8 +9074,6 @@ the top of the viewport and Y increases as it proceeds towards the bottom of the "Animation.trackingStart": Animation.trackingStartPayload; "Animation.trackingUpdate": Animation.trackingUpdatePayload; "Animation.trackingComplete": Animation.trackingCompletePayload; - "ApplicationCache.applicationCacheStatusUpdated": ApplicationCache.applicationCacheStatusUpdatedPayload; - "ApplicationCache.networkStateUpdated": ApplicationCache.networkStateUpdatedPayload; "Browser.extensionsEnabled": Browser.extensionsEnabledPayload; "Browser.extensionsDisabled": Browser.extensionsDisabledPayload; "CPUProfiler.trackingStart": CPUProfiler.trackingStartPayload; @@ -9324,7 +9123,6 @@ the top of the viewport and Y increases as it proceeds towards the bottom of the "DOMStorage.domStorageItemRemoved": DOMStorage.domStorageItemRemovedPayload; "DOMStorage.domStorageItemAdded": DOMStorage.domStorageItemAddedPayload; "DOMStorage.domStorageItemUpdated": DOMStorage.domStorageItemUpdatedPayload; - "Database.addDatabase": Database.addDatabasePayload; "Debugger.globalObjectCleared": Debugger.globalObjectClearedPayload; "Debugger.scriptParsed": Debugger.scriptParsedPayload; "Debugger.scriptFailedToParse": Debugger.scriptFailedToParsePayload; @@ -9406,11 +9204,6 @@ the top of the viewport and Y increases as it proceeds towards the bottom of the "Animation.resolveAnimation": Animation.resolveAnimationParameters; "Animation.startTracking": Animation.startTrackingParameters; "Animation.stopTracking": Animation.stopTrackingParameters; - "ApplicationCache.getFramesWithManifests": ApplicationCache.getFramesWithManifestsParameters; - "ApplicationCache.enable": ApplicationCache.enableParameters; - "ApplicationCache.disable": ApplicationCache.disableParameters; - "ApplicationCache.getManifestForFrame": ApplicationCache.getManifestForFrameParameters; - "ApplicationCache.getApplicationCacheForFrame": ApplicationCache.getApplicationCacheForFrameParameters; "Audit.setup": Audit.setupParameters; "Audit.run": Audit.runParameters; "Audit.teardown": Audit.teardownParameters; @@ -9520,10 +9313,6 @@ the top of the viewport and Y increases as it proceeds towards the bottom of the "DOMStorage.setDOMStorageItem": DOMStorage.setDOMStorageItemParameters; "DOMStorage.removeDOMStorageItem": DOMStorage.removeDOMStorageItemParameters; "DOMStorage.clearDOMStorageItems": DOMStorage.clearDOMStorageItemsParameters; - "Database.enable": Database.enableParameters; - "Database.disable": Database.disableParameters; - "Database.getDatabaseTableNames": Database.getDatabaseTableNamesParameters; - "Database.executeSQL": Database.executeSQLParameters; "Debugger.enable": Debugger.enableParameters; "Debugger.disable": Debugger.disableParameters; "Debugger.setAsyncStackTraceDepth": Debugger.setAsyncStackTraceDepthParameters; @@ -9658,6 +9447,7 @@ the top of the viewport and Y increases as it proceeds towards the bottom of the "Playwright.grantFileReadAccess": Playwright.grantFileReadAccessParameters; "Playwright.takePageScreenshot": Playwright.takePageScreenshotParameters; "Playwright.setIgnoreCertificateErrors": Playwright.setIgnoreCertificateErrorsParameters; + "Playwright.setPageZoomFactor": Playwright.setPageZoomFactorParameters; "Playwright.getAllCookies": Playwright.getAllCookiesParameters; "Playwright.setCookies": Playwright.setCookiesParameters; "Playwright.deleteAllCookies": Playwright.deleteAllCookiesParameters; @@ -9718,11 +9508,6 @@ the top of the viewport and Y increases as it proceeds towards the bottom of the "Animation.resolveAnimation": Animation.resolveAnimationReturnValue; "Animation.startTracking": Animation.startTrackingReturnValue; "Animation.stopTracking": Animation.stopTrackingReturnValue; - "ApplicationCache.getFramesWithManifests": ApplicationCache.getFramesWithManifestsReturnValue; - "ApplicationCache.enable": ApplicationCache.enableReturnValue; - "ApplicationCache.disable": ApplicationCache.disableReturnValue; - "ApplicationCache.getManifestForFrame": ApplicationCache.getManifestForFrameReturnValue; - "ApplicationCache.getApplicationCacheForFrame": ApplicationCache.getApplicationCacheForFrameReturnValue; "Audit.setup": Audit.setupReturnValue; "Audit.run": Audit.runReturnValue; "Audit.teardown": Audit.teardownReturnValue; @@ -9832,10 +9617,6 @@ the top of the viewport and Y increases as it proceeds towards the bottom of the "DOMStorage.setDOMStorageItem": DOMStorage.setDOMStorageItemReturnValue; "DOMStorage.removeDOMStorageItem": DOMStorage.removeDOMStorageItemReturnValue; "DOMStorage.clearDOMStorageItems": DOMStorage.clearDOMStorageItemsReturnValue; - "Database.enable": Database.enableReturnValue; - "Database.disable": Database.disableReturnValue; - "Database.getDatabaseTableNames": Database.getDatabaseTableNamesReturnValue; - "Database.executeSQL": Database.executeSQLReturnValue; "Debugger.enable": Debugger.enableReturnValue; "Debugger.disable": Debugger.disableReturnValue; "Debugger.setAsyncStackTraceDepth": Debugger.setAsyncStackTraceDepthReturnValue; @@ -9970,6 +9751,7 @@ the top of the viewport and Y increases as it proceeds towards the bottom of the "Playwright.grantFileReadAccess": Playwright.grantFileReadAccessReturnValue; "Playwright.takePageScreenshot": Playwright.takePageScreenshotReturnValue; "Playwright.setIgnoreCertificateErrors": Playwright.setIgnoreCertificateErrorsReturnValue; + "Playwright.setPageZoomFactor": Playwright.setPageZoomFactorReturnValue; "Playwright.getAllCookies": Playwright.getAllCookiesReturnValue; "Playwright.setCookies": Playwright.setCookiesReturnValue; "Playwright.deleteAllCookies": Playwright.deleteAllCookiesReturnValue; diff --git a/packages/playwright-core/src/server/webkit/webkit.ts b/packages/playwright-core/src/server/webkit/webkit.ts index 5159f8cecb9ee..5b5519264cc2c 100644 --- a/packages/playwright-core/src/server/webkit/webkit.ts +++ b/packages/playwright-core/src/server/webkit/webkit.ts @@ -15,17 +15,19 @@ * limitations under the License. */ -import { WKBrowser } from '../webkit/wkBrowser'; -import type { Env } from '../../utils/processLauncher'; import path from 'path'; + import { kBrowserCloseMessageId } from './wkConnection'; +import { wrapInASCIIBox } from '../utils/ascii'; import { BrowserType, kNoXServerRunningError } from '../browserType'; -import type { ConnectionTransport } from '../transport'; +import { WKBrowser } from '../webkit/wkBrowser'; + import type { BrowserOptions } from '../browser'; -import type * as types from '../types'; -import { wrapInASCIIBox } from '../../utils'; import type { SdkObject } from '../instrumentation'; +import type { Env } from '../utils/processLauncher'; import type { ProtocolError } from '../protocolError'; +import type { ConnectionTransport } from '../transport'; +import type * as types from '../types'; export class WebKit extends BrowserType { constructor(parent: SdkObject) { diff --git a/packages/playwright-core/src/server/webkit/wkAccessibility.ts b/packages/playwright-core/src/server/webkit/wkAccessibility.ts index 80c855ea7b852..52b9199df55bc 100644 --- a/packages/playwright-core/src/server/webkit/wkAccessibility.ts +++ b/packages/playwright-core/src/server/webkit/wkAccessibility.ts @@ -14,8 +14,8 @@ * limitations under the License. */ import type * as accessibility from '../accessibility'; -import type { WKSession } from './wkConnection'; import type { Protocol } from './protocol'; +import type { WKSession } from './wkConnection'; import type * as dom from '../dom'; import type * as channels from '@protocol/channels'; diff --git a/packages/playwright-core/src/server/webkit/wkBrowser.ts b/packages/playwright-core/src/server/webkit/wkBrowser.ts index 86833088d8e3d..5af64c8bb412d 100644 --- a/packages/playwright-core/src/server/webkit/wkBrowser.ts +++ b/packages/playwright-core/src/server/webkit/wkBrowser.ts @@ -15,24 +15,25 @@ * limitations under the License. */ -import type { BrowserOptions } from '../browser'; -import { Browser } from '../browser'; -import { assertBrowserContextIsNotOwned, BrowserContext, verifyGeolocation } from '../browserContext'; import { assert } from '../../utils'; +import { Browser } from '../browser'; +import { BrowserContext, assertBrowserContextIsNotOwned, verifyGeolocation } from '../browserContext'; import * as network from '../network'; +import { WKConnection, WKSession, kPageProxyMessageReceived } from './wkConnection'; +import { WKPage } from './wkPage'; +import { TargetClosedError } from '../errors'; + +import type { BrowserOptions } from '../browser'; +import type { SdkObject } from '../instrumentation'; import type { InitScript, Page } from '../page'; import type { ConnectionTransport } from '../transport'; import type * as types from '../types'; -import type * as channels from '@protocol/channels'; import type { Protocol } from './protocol'; import type { PageProxyMessageReceivedPayload } from './wkConnection'; -import { kPageProxyMessageReceived, WKConnection, WKSession } from './wkConnection'; -import { WKPage } from './wkPage'; -import { TargetClosedError } from '../errors'; -import type { SdkObject } from '../instrumentation'; +import type * as channels from '@protocol/channels'; -const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Safari/605.1.15'; -const BROWSER_VERSION = '18.2'; +const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.4 Safari/605.1.15'; +const BROWSER_VERSION = '18.4'; export class WKBrowser extends Browser { private readonly _connection: WKConnection; diff --git a/packages/playwright-core/src/server/webkit/wkConnection.ts b/packages/playwright-core/src/server/webkit/wkConnection.ts index a2bbed11213a4..ada50a413b1ba 100644 --- a/packages/playwright-core/src/server/webkit/wkConnection.ts +++ b/packages/playwright-core/src/server/webkit/wkConnection.ts @@ -16,14 +16,17 @@ */ import { EventEmitter } from 'events'; + import { assert } from '../../utils'; +import { debugLogger } from '../utils/debugLogger'; +import { helper } from '../helper'; +import { ProtocolError } from '../protocolError'; + import type { ConnectionTransport, ProtocolRequest, ProtocolResponse } from '../transport'; import type { Protocol } from './protocol'; -import type { RecentLogsCollector } from '../../utils/debugLogger'; -import { debugLogger } from '../../utils/debugLogger'; +import type { RecentLogsCollector } from '../utils/debugLogger'; import type { ProtocolLogger } from '../types'; -import { helper } from '../helper'; -import { ProtocolError } from '../protocolError'; + // WKPlaywright uses this special id to issue Browser.close command which we // should ignore. diff --git a/packages/playwright-core/src/server/webkit/wkExecutionContext.ts b/packages/playwright-core/src/server/webkit/wkExecutionContext.ts index 2b75745cbd8d0..c7533d1ac5967 100644 --- a/packages/playwright-core/src/server/webkit/wkExecutionContext.ts +++ b/packages/playwright-core/src/server/webkit/wkExecutionContext.ts @@ -15,11 +15,14 @@ * limitations under the License. */ -import type { WKSession } from './wkConnection'; -import type { Protocol } from './protocol'; -import * as js from '../javascript'; import { parseEvaluationResultValue } from '../isomorphic/utilityScriptSerializers'; +import * as js from '../javascript'; +import * as dom from '../dom'; import { isSessionClosedError } from '../protocolError'; +import { assert } from '../../utils/isomorphic/assert'; + +import type { Protocol } from './protocol'; +import type { WKSession } from './wkConnection'; export class WKExecutionContext implements js.ExecutionContextDelegate { private readonly _session: WKSession; @@ -45,7 +48,7 @@ export class WKExecutionContext implements js.ExecutionContextDelegate { } } - async rawEvaluateHandle(expression: string): Promise { + async rawEvaluateHandle(context: js.ExecutionContext, expression: string): Promise { try { const response = await this._session.send('Runtime.evaluate', { expression, @@ -54,13 +57,13 @@ export class WKExecutionContext implements js.ExecutionContextDelegate { }); if (response.wasThrown) throw new js.JavaScriptErrorInEvaluate(response.result.description); - return response.result.objectId!; + return createHandle(context, response.result); } catch (error) { throw rewriteError(error); } } - async evaluateWithArguments(expression: string, returnByValue: boolean, utilityScript: js.JSHandle, values: any[], objectIds: string[]): Promise { + async evaluateWithArguments(expression: string, returnByValue: boolean, utilityScript: js.JSHandle, values: any[], handles: js.JSHandle[]): Promise { try { const response = await this._session.send('Runtime.callFunctionOn', { functionDeclaration: expression, @@ -68,7 +71,7 @@ export class WKExecutionContext implements js.ExecutionContextDelegate { arguments: [ { objectId: utilityScript._objectId }, ...values.map(value => ({ value })), - ...objectIds.map(objectId => ({ objectId })), + ...handles.map(handle => ({ objectId: handle._objectId! })), ], returnByValue, emulateUserGesture: true, @@ -78,33 +81,30 @@ export class WKExecutionContext implements js.ExecutionContextDelegate { throw new js.JavaScriptErrorInEvaluate(response.result.description); if (returnByValue) return parseEvaluationResultValue(response.result.value); - return utilityScript._context.createHandle(response.result); + return createHandle(utilityScript._context, response.result); } catch (error) { throw rewriteError(error); } } - async getProperties(context: js.ExecutionContext, objectId: js.ObjectId): Promise> { + async getProperties(object: js.JSHandle): Promise> { const response = await this._session.send('Runtime.getProperties', { - objectId, + objectId: object._objectId!, ownProperties: true }); const result = new Map(); for (const property of response.properties) { if (!property.enumerable || !property.value) continue; - result.set(property.name, context.createHandle(property.value)); + result.set(property.name, createHandle(object._context, property.value)); } return result; } - createHandle(context: js.ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject): js.JSHandle { - const isPromise = remoteObject.className === 'Promise'; - return new js.JSHandle(context, isPromise ? 'promise' : remoteObject.subtype || remoteObject.type, renderPreview(remoteObject), remoteObject.objectId, potentiallyUnserializableValue(remoteObject)); - } - - async releaseHandle(objectId: js.ObjectId): Promise { - await this._session.send('Runtime.releaseObject', { objectId }); + async releaseHandle(handle: js.JSHandle): Promise { + if (!handle._objectId) + return; + await this._session.send('Runtime.releaseObject', { objectId: handle._objectId }); } } @@ -138,3 +138,12 @@ function renderPreview(object: Protocol.Runtime.RemoteObject): string | undefine return js.sparseArrayToString(object.preview.properties!); return object.description; } + +export function createHandle(context: js.ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject): js.JSHandle { + if (remoteObject.subtype === 'node') { + assert(context instanceof dom.FrameExecutionContext); + return new dom.ElementHandle(context as dom.FrameExecutionContext, remoteObject.objectId!); + } + const isPromise = remoteObject.className === 'Promise'; + return new js.JSHandle(context, isPromise ? 'promise' : remoteObject.subtype || remoteObject.type, renderPreview(remoteObject), remoteObject.objectId, potentiallyUnserializableValue(remoteObject)); +} diff --git a/packages/playwright-core/src/server/webkit/wkInput.ts b/packages/playwright-core/src/server/webkit/wkInput.ts index 5769fd6465b8f..1e4ccf6b0b836 100644 --- a/packages/playwright-core/src/server/webkit/wkInput.ts +++ b/packages/playwright-core/src/server/webkit/wkInput.ts @@ -15,11 +15,12 @@ * limitations under the License. */ +import { isString } from '../../utils'; import * as input from '../input'; -import type * as types from '../types'; import { macEditingCommands } from '../macEditingCommands'; + +import type * as types from '../types'; import type { WKSession } from './wkConnection'; -import { isString } from '../../utils'; import type { Page } from '../page'; function toModifiersMask(modifiers: Set): number { diff --git a/packages/playwright-core/src/server/webkit/wkInterceptableRequest.ts b/packages/playwright-core/src/server/webkit/wkInterceptableRequest.ts index 93367726ed5ae..45494d6cc9733 100644 --- a/packages/playwright-core/src/server/webkit/wkInterceptableRequest.ts +++ b/packages/playwright-core/src/server/webkit/wkInterceptableRequest.ts @@ -15,12 +15,14 @@ * limitations under the License. */ -import type * as frames from '../frames'; +import { assert, headersArrayToObject, headersObjectToArray } from '../../utils'; import * as network from '../network'; + +import type * as frames from '../frames'; import type * as types from '../types'; import type { Protocol } from './protocol'; import type { WKSession } from './wkConnection'; -import { assert, headersObjectToArray, headersArrayToObject } from '../../utils'; + const errorReasons: { [reason: string]: Protocol.Network.ResourceErrorType } = { 'aborted': 'Cancellation', diff --git a/packages/playwright-core/src/server/webkit/wkPage.ts b/packages/playwright-core/src/server/webkit/wkPage.ts index 15005f589b5fe..9fae9d0002e0d 100644 --- a/packages/playwright-core/src/server/webkit/wkPage.ts +++ b/packages/playwright-core/src/server/webkit/wkPage.ts @@ -16,35 +16,40 @@ */ import path from 'path'; + +import { assert } from '../../utils'; +import { headersArrayToObject } from '../../utils/isomorphic/headers'; +import { createGuid } from '../utils/crypto'; +import { eventsHelper } from '../utils/eventsHelper'; +import { hostPlatform } from '../utils/hostPlatform'; +import { splitErrorMessage } from '../../utils/isomorphic/stackTrace'; import { PNG, jpegjs } from '../../utilsBundle'; -import { splitErrorMessage } from '../../utils/stackTrace'; -import { assert, createGuid, debugAssert, headersArrayToObject } from '../../utils'; -import { hostPlatform } from '../../utils/hostPlatform'; -import type * as accessibility from '../accessibility'; +import { BrowserContext } from '../browserContext'; import * as dialog from '../dialog'; import * as dom from '../dom'; -import type * as frames from '../frames'; -import type { RegisteredListener } from '../../utils/eventsHelper'; -import { eventsHelper } from '../../utils/eventsHelper'; +import { TargetClosedError } from '../errors'; import { helper } from '../helper'; -import type { JSHandle } from '../javascript'; import * as network from '../network'; -import { type InitScript, PageBinding, type PageDelegate } from '../page'; +import { PageBinding } from '../page'; import { Page } from '../page'; -import type { Progress } from '../progress'; -import type * as types from '../types'; -import type { Protocol } from './protocol'; import { getAccessibilityTree } from './wkAccessibility'; -import type { WKBrowserContext } from './wkBrowser'; import { WKSession } from './wkConnection'; -import { WKExecutionContext } from './wkExecutionContext'; +import { createHandle, WKExecutionContext } from './wkExecutionContext'; import { RawKeyboardImpl, RawMouseImpl, RawTouchscreenImpl } from './wkInput'; import { WKInterceptableRequest, WKRouteImpl } from './wkInterceptableRequest'; import { WKProvisionalPage } from './wkProvisionalPage'; import { WKWorkers } from './wkWorkers'; -import { debugLogger } from '../../utils/debugLogger'; -import { BrowserContext } from '../browserContext'; -import { TargetClosedError } from '../errors'; +import { debugLogger } from '../utils/debugLogger'; + +import type { Protocol } from './protocol'; +import type { WKBrowserContext } from './wkBrowser'; +import type { RegisteredListener } from '../utils/eventsHelper'; +import type * as accessibility from '../accessibility'; +import type * as frames from '../frames'; +import type { JSHandle } from '../javascript'; +import type { InitScript, PageDelegate } from '../page'; +import type { Progress } from '../progress'; +import type * as types from '../types'; const UTILITY_WORLD_NAME = '__playwright_utility_world__'; @@ -191,8 +196,8 @@ export class WKPage implements PageDelegate { if (contextOptions.userAgent) promises.push(this.updateUserAgent()); const emulatedMedia = this._page.emulatedMedia(); - if (emulatedMedia.media || emulatedMedia.colorScheme || emulatedMedia.reducedMotion || emulatedMedia.forcedColors) - promises.push(WKPage._setEmulateMedia(session, emulatedMedia.media, emulatedMedia.colorScheme, emulatedMedia.reducedMotion, emulatedMedia.forcedColors)); + if (emulatedMedia.media || emulatedMedia.colorScheme || emulatedMedia.reducedMotion || emulatedMedia.forcedColors || emulatedMedia.contrast) + promises.push(WKPage._setEmulateMedia(session, emulatedMedia.media, emulatedMedia.colorScheme, emulatedMedia.reducedMotion, emulatedMedia.forcedColors, emulatedMedia.contrast)); const bootstrapScript = this._calculateBootstrapScript(); if (bootstrapScript.length) promises.push(session.send('Page.setBootstrapScript', { source: bootstrapScript })); @@ -289,7 +294,6 @@ export class WKPage implements PageDelegate { } handleWindowOpen(event: Protocol.Playwright.windowOpenPayload) { - debugAssert(!this._nextWindowOpenPopupFeatures); this._nextWindowOpenPopupFeatures = event.windowFeatures; } @@ -492,7 +496,6 @@ export class WKPage implements PageDelegate { else if (contextPayload.type === 'user' && contextPayload.name === UTILITY_WORLD_NAME) worldName = 'utility'; const context = new dom.FrameExecutionContext(delegate, frame, worldName); - (context as any)[contextDelegateSymbol] = delegate; if (worldName) frame._contextCreated(worldName, context); this._contextIdToContext.set(contextPayload.id, context); @@ -558,7 +561,7 @@ export class WKPage implements PageDelegate { } if (!context) return; - handles.push(context.createHandle(p)); + handles.push(createHandle(context, p)); } this._lastConsoleMessage = { derivedType, @@ -607,7 +610,7 @@ export class WKPage implements PageDelegate { let handle; try { const context = await this._page._frameManager.frame(event.frameId)!._mainContext(); - handle = context.createHandle(event.element).asElement()!; + handle = createHandle(context, event.element).asElement()!; } catch (e) { // During async processing, frame/context may go away. We should not throw. return; @@ -615,7 +618,7 @@ export class WKPage implements PageDelegate { await this._page._onFileChooserOpened(handle); } - private static async _setEmulateMedia(session: WKSession, mediaType: types.MediaType, colorScheme: types.ColorScheme, reducedMotion: types.ReducedMotion, forcedColors: types.ForcedColors): Promise { + private static async _setEmulateMedia(session: WKSession, mediaType: types.MediaType, colorScheme: types.ColorScheme, reducedMotion: types.ReducedMotion, forcedColors: types.ForcedColors, contrast: types.Contrast): Promise { const promises = []; promises.push(session.send('Page.setEmulatedMedia', { media: mediaType === 'no-override' ? '' : mediaType })); let appearance: any = undefined; @@ -639,6 +642,13 @@ export class WKPage implements PageDelegate { case 'no-override': forcedColorsWk = undefined; break; } promises.push(session.send('Page.setForcedColors', { forcedColors: forcedColorsWk })); + let contrastWk: any = undefined; + switch (contrast) { + case 'more': contrastWk = 'More'; break; + case 'no-preference': contrastWk = 'NoPreference'; break; + case 'no-override': contrastWk = undefined; break; + } + promises.push(session.send('Page.overrideUserPreference', { name: 'PrefersContrast', value: contrastWk })); await Promise.all(promises); } @@ -661,7 +671,8 @@ export class WKPage implements PageDelegate { const colorScheme = emulatedMedia.colorScheme; const reducedMotion = emulatedMedia.reducedMotion; const forcedColors = emulatedMedia.forcedColors; - await this._forAllSessions(session => WKPage._setEmulateMedia(session, emulatedMedia.media, colorScheme, reducedMotion, forcedColors)); + const contrast = emulatedMedia.contrast; + await this._forAllSessions(session => WKPage._setEmulateMedia(session, emulatedMedia.media, colorScheme, reducedMotion, forcedColors, contrast)); } async updateEmulatedViewportSize(): Promise { @@ -857,10 +868,6 @@ export class WKPage implements PageDelegate { return nodeInfo.ownerFrameId || null; } - isElementHandle(remoteObject: any): boolean { - return (remoteObject as Protocol.Runtime.RemoteObject).subtype === 'node'; - } - async getBoundingBox(handle: dom.ElementHandle): Promise { const quads = await this.getContentQuads(handle); if (!quads || !quads.length) @@ -934,16 +941,6 @@ export class WKPage implements PageDelegate { ]); } - async setInputFiles(handle: dom.ElementHandle, files: types.FilePayload[]): Promise { - const objectId = handle._objectId; - const protocolFiles = files.map(file => ({ - name: file.name, - type: file.mimeType, - data: file.buffer, - })); - await this._session.send('DOM.setInputFiles', { objectId, files: protocolFiles }); - } - async setInputFilePaths(handle: dom.ElementHandle, paths: string[]): Promise { const pageProxyId = this._pageProxySession.sessionId; const objectId = handle._objectId; @@ -956,11 +953,11 @@ export class WKPage implements PageDelegate { async adoptElementHandle(handle: dom.ElementHandle, to: dom.FrameExecutionContext): Promise> { const result = await this._session.sendMayFail('DOM.resolveNode', { objectId: handle._objectId, - executionContextId: ((to as any)[contextDelegateSymbol] as WKExecutionContext)._contextId + executionContextId: (to.delegate as WKExecutionContext)._contextId }); if (!result || result.object.subtype === 'null') throw new Error(dom.kUnableToAdoptErrorMessage); - return to.createHandle(result.object) as dom.ElementHandle; + return createHandle(to, result.object) as dom.ElementHandle; } async getAccessibilityTree(needle?: dom.ElementHandle): Promise<{tree: accessibility.AXNode, needle: accessibility.AXNode | null}> { @@ -980,11 +977,11 @@ export class WKPage implements PageDelegate { const context = await parent._mainContext(); const result = await this._session.send('DOM.resolveNode', { frameId: frame._id, - executionContextId: ((context as any)[contextDelegateSymbol] as WKExecutionContext)._contextId + executionContextId: (context.delegate as WKExecutionContext)._contextId }); if (!result || result.object.subtype === 'null') throw new Error('Frame has been detached.'); - return context.createHandle(result.object) as dom.ElementHandle; + return createHandle(context, result.object) as dom.ElementHandle; } private _maybeCancelCoopNavigationRequest(provisionalPage: WKProvisionalPage) { @@ -1255,5 +1252,3 @@ function isLoadedSecurely(url: string, timing: network.ResourceTiming) { return true; } catch (_) {} } - -const contextDelegateSymbol = Symbol('delegate'); diff --git a/packages/playwright-core/src/server/webkit/wkProvisionalPage.ts b/packages/playwright-core/src/server/webkit/wkProvisionalPage.ts index 6d7459c978c35..63d4cc6f0a38d 100644 --- a/packages/playwright-core/src/server/webkit/wkProvisionalPage.ts +++ b/packages/playwright-core/src/server/webkit/wkProvisionalPage.ts @@ -14,12 +14,13 @@ * limitations under the License. */ +import { assert } from '../../utils'; +import { eventsHelper } from '../utils/eventsHelper'; + +import type { Protocol } from './protocol'; import type { WKSession } from './wkConnection'; import type { WKPage } from './wkPage'; -import type { RegisteredListener } from '../../utils/eventsHelper'; -import { eventsHelper } from '../../utils/eventsHelper'; -import type { Protocol } from './protocol'; -import { assert } from '../../utils'; +import type { RegisteredListener } from '../utils/eventsHelper'; import type * as network from '../network'; export class WKProvisionalPage { diff --git a/packages/playwright-core/src/server/webkit/wkWorkers.ts b/packages/playwright-core/src/server/webkit/wkWorkers.ts index ae69b72f8a945..dc7c633433f2d 100644 --- a/packages/playwright-core/src/server/webkit/wkWorkers.ts +++ b/packages/playwright-core/src/server/webkit/wkWorkers.ts @@ -14,13 +14,14 @@ * limitations under the License. */ -import type { RegisteredListener } from '../../utils/eventsHelper'; -import { eventsHelper } from '../../utils/eventsHelper'; -import type { Page } from '../page'; +import { eventsHelper } from '../utils/eventsHelper'; import { Worker } from '../page'; -import type { Protocol } from './protocol'; import { WKSession } from './wkConnection'; -import { WKExecutionContext } from './wkExecutionContext'; +import { createHandle, WKExecutionContext } from './wkExecutionContext'; + +import type { Protocol } from './protocol'; +import type { RegisteredListener } from '../utils/eventsHelper'; +import type { Page } from '../page'; import type * as types from '../types'; export class WKWorkers { @@ -94,7 +95,7 @@ export class WKWorkers { derivedType = 'timeEnd'; const handles = (parameters || []).map(p => { - return worker._existingExecutionContext!.createHandle(p); + return createHandle(worker._existingExecutionContext!, p); }); const location: types.ConsoleMessageLocation = { url: url || '', diff --git a/packages/playwright-core/src/utils.ts b/packages/playwright-core/src/utils.ts new file mode 100644 index 0000000000000..4f2f04fc110fb --- /dev/null +++ b/packages/playwright-core/src/utils.ts @@ -0,0 +1,55 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './utils/isomorphic/colors'; +export * from './utils/isomorphic/assert'; +export * from './utils/isomorphic/headers'; +export * from './utils/isomorphic/locatorGenerators'; +export * from './utils/isomorphic/manualPromise'; +export * from './utils/isomorphic/mimeType'; +export * from './utils/isomorphic/multimap'; +export * from './utils/isomorphic/rtti'; +export * from './utils/isomorphic/semaphore'; +export * from './utils/isomorphic/stackTrace'; +export * from './utils/isomorphic/stringUtils'; +export * from './utils/isomorphic/time'; +export * from './utils/isomorphic/timeoutRunner'; +export * from './utils/isomorphic/urlMatch'; + +export * from './server/utils/ascii'; +export * from './server/utils/comparators'; +export * from './server/utils/crypto'; +export * from './server/utils/debug'; +export * from './server/utils/debugLogger'; +export * from './server/utils/env'; +export * from './server/utils/eventsHelper'; +export * from './server/utils/expectUtils'; +export * from './server/utils/fileUtils'; +export * from './server/utils/hostPlatform'; +export * from './server/utils/httpServer'; +export * from './server/utils/network'; +export * from './server/utils/nodePlatform'; +export * from './server/utils/processLauncher'; +export * from './server/utils/profiler'; +export * from './server/utils/socksProxy'; +export * from './server/utils/spawnAsync'; +export * from './server/utils/task'; +export * from './server/utils/userAgent'; +export * from './server/utils/wsServer'; +export * from './server/utils/zipFile'; +export * from './server/utils/zones'; + +export { colors } from './utilsBundle'; diff --git a/packages/playwright-core/src/utils/DEPS.list b/packages/playwright-core/src/utils/DEPS.list index 7cfdafe4a1ca4..8a14701d4d54c 100644 --- a/packages/playwright-core/src/utils/DEPS.list +++ b/packages/playwright-core/src/utils/DEPS.list @@ -1,6 +1,6 @@ [*] ./ -../third_party/pixelmatch -../image_tools/compare.ts +./isomorphic ../utilsBundle.ts ../zipBundle.ts +../utils/isomorphic \ No newline at end of file diff --git a/packages/playwright-core/src/utils/index.ts b/packages/playwright-core/src/utils/index.ts deleted file mode 100644 index 0bc7a75b08e5e..0000000000000 --- a/packages/playwright-core/src/utils/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export * from './ascii'; -export * from './comparators'; -export * from './crypto'; -export * from './debug'; -export * from './debugLogger'; -export * from './env'; -export * from './eventsHelper'; -export * from './expectUtils'; -export * from './fileUtils'; -export * from './headers'; -export * from './hostPlatform'; -export * from './httpServer'; -export * from './manualPromise'; -export * from './isomorphic/locatorGenerators'; -export * from './isomorphic/mimeType'; -export * from './isomorphic/stringUtils'; -export * from './isomorphic/urlMatch'; -export * from './multimap'; -export * from './network'; -export * from './processLauncher'; -export * from './profiler'; -export * from './rtti'; -export * from './semaphore'; -export * from './spawnAsync'; -export * from './stackTrace'; -export * from './task'; -export * from './time'; -export * from './timeoutRunner'; -export * from './traceUtils'; -export * from './userAgent'; -export * from './wsServer'; -export * from './zipFile'; -export * from './zones'; diff --git a/packages/playwright-core/src/utils/isomorphic/ariaSnapshot.ts b/packages/playwright-core/src/utils/isomorphic/ariaSnapshot.ts index 7ffe9b4de9f3e..5fbc23ec44c78 100644 --- a/packages/playwright-core/src/utils/isomorphic/ariaSnapshot.ts +++ b/packages/playwright-core/src/utils/isomorphic/ariaSnapshot.ts @@ -220,7 +220,8 @@ export function parseAriaSnapshot(yaml: YamlLibrary, text: string, options: yaml const emptyFragment: AriaTemplateRoleNode = { kind: 'role', role: 'fragment' }; function normalizeWhitespace(text: string) { - return text.replace(/[\r\n\s\t]+/g, ' ').trim(); + // TODO: why is this different from normalizeWhitespace in stringUtils.ts? + return text.replace(/[\u200b\u00ad]/g, '').replace(/[\r\n\s\t]+/g, ' ').trim(); } export function valueOrRegex(value: string): string | AriaRegex { diff --git a/packages/playwright-core/src/utils/isomorphic/assert.ts b/packages/playwright-core/src/utils/isomorphic/assert.ts new file mode 100644 index 0000000000000..bd0c38d413c3e --- /dev/null +++ b/packages/playwright-core/src/utils/isomorphic/assert.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function assert(value: any, message?: string): asserts value { + if (!value) + throw new Error(message || 'Assertion error'); +} diff --git a/packages/playwright-core/src/utils/isomorphic/colors.ts b/packages/playwright-core/src/utils/isomorphic/colors.ts new file mode 100644 index 0000000000000..7be0955ad3a49 --- /dev/null +++ b/packages/playwright-core/src/utils/isomorphic/colors.ts @@ -0,0 +1,66 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const webColors = { + enabled: true, + reset: (text: string) => applyStyle(0, 0, text), + + bold: (text: string) => applyStyle(1, 22, text), + dim: (text: string) => applyStyle(2, 22, text), + italic: (text: string) => applyStyle(3, 23, text), + underline: (text: string) => applyStyle(4, 24, text), + inverse: (text: string) => applyStyle(7, 27, text), + hidden: (text: string) => applyStyle(8, 28, text), + strikethrough: (text: string) => applyStyle(9, 29, text), + + black: (text: string) => applyStyle(30, 39, text), + red: (text: string) => applyStyle(31, 39, text), + green: (text: string) => applyStyle(32, 39, text), + yellow: (text: string) => applyStyle(33, 39, text), + blue: (text: string) => applyStyle(34, 39, text), + magenta: (text: string) => applyStyle(35, 39, text), + cyan: (text: string) => applyStyle(36, 39, text), + white: (text: string) => applyStyle(37, 39, text), + gray: (text: string) => applyStyle(90, 39, text), + grey: (text: string) => applyStyle(90, 39, text), +}; + +export type Colors = typeof webColors; + +export const noColors: Colors = { + enabled: false, + reset: t => t, + bold: t => t, + dim: t => t, + italic: t => t, + underline: t => t, + inverse: t => t, + hidden: t => t, + strikethrough: t => t, + black: t => t, + red: t => t, + green: t => t, + yellow: t => t, + blue: t => t, + magenta: t => t, + cyan: t => t, + white: t => t, + gray: t => t, + grey: t => t, +}; + + +const applyStyle = (open: number, close: number, text: string) => `\u001b[${open}m${text}\u001b[${close}m`; diff --git a/packages/playwright-core/src/utils/headers.ts b/packages/playwright-core/src/utils/isomorphic/headers.ts similarity index 100% rename from packages/playwright-core/src/utils/headers.ts rename to packages/playwright-core/src/utils/isomorphic/headers.ts diff --git a/packages/playwright-core/src/utils/isomorphic/locatorGenerators.ts b/packages/playwright-core/src/utils/isomorphic/locatorGenerators.ts index 355d0cec5fa0d..5be1f36b96109 100644 --- a/packages/playwright-core/src/utils/isomorphic/locatorGenerators.ts +++ b/packages/playwright-core/src/utils/isomorphic/locatorGenerators.ts @@ -14,12 +14,14 @@ * limitations under the License. */ +import { parseAttributeSelector, parseSelector, stringifySelector } from './selectorParser'; import { escapeWithQuotes, normalizeEscapedRegexQuotes, toSnakeCase, toTitleCase } from './stringUtils'; -import { type NestedSelectorBody, parseAttributeSelector, parseSelector, stringifySelector } from './selectorParser'; + +import type { NestedSelectorBody } from './selectorParser'; import type { ParsedSelector } from './selectorParser'; export type Language = 'javascript' | 'python' | 'java' | 'csharp' | 'jsonl'; -export type LocatorType = 'default' | 'role' | 'text' | 'label' | 'placeholder' | 'alt' | 'title' | 'test-id' | 'nth' | 'first' | 'last' | 'has-text' | 'has-not-text' | 'has' | 'hasNot' | 'frame' | 'frame-locator' | 'and' | 'or' | 'chain'; +export type LocatorType = 'default' | 'role' | 'text' | 'label' | 'placeholder' | 'alt' | 'title' | 'test-id' | 'nth' | 'first' | 'last' | 'visible' | 'has-text' | 'has-not-text' | 'has' | 'hasNot' | 'frame' | 'frame-locator' | 'and' | 'or' | 'chain'; export type LocatorBase = 'page' | 'locator' | 'frame-locator'; export type Quote = '\'' | '"' | '`'; @@ -66,6 +68,10 @@ function innerAsLocators(factory: LocatorFactory, parsed: ParsedSelector, isFram tokens.push([factory.generateLocator(base, 'nth', part.body as string)]); continue; } + if (part.name === 'visible') { + tokens.push([factory.generateLocator(base, 'visible', part.body as string), factory.generateLocator(base, 'default', `visible=${part.body}`)]); + continue; + } if (part.name === 'internal:text') { const { exact, text } = detectExact(part.body as string); tokens.push([factory.generateLocator(base, 'text', text, { exact })]); @@ -273,6 +279,8 @@ export class JavaScriptLocatorFactory implements LocatorFactory { return `first()`; case 'last': return `last()`; + case 'visible': + return `filter({ visible: ${body === 'true' ? 'true' : 'false'} })`; case 'role': const attrs: string[] = []; if (isRegExp(options.name)) { @@ -367,6 +375,8 @@ export class PythonLocatorFactory implements LocatorFactory { return `first`; case 'last': return `last`; + case 'visible': + return `filter(visible=${body === 'true' ? 'True' : 'False'})`; case 'role': const attrs: string[] = []; if (isRegExp(options.name)) { @@ -474,6 +484,8 @@ export class JavaLocatorFactory implements LocatorFactory { return `first()`; case 'last': return `last()`; + case 'visible': + return `filter(new ${clazz}.FilterOptions().setVisible(${body === 'true' ? 'true' : 'false'}))`; case 'role': const attrs: string[] = []; if (isRegExp(options.name)) { @@ -571,6 +583,8 @@ export class CSharpLocatorFactory implements LocatorFactory { return `First`; case 'last': return `Last`; + case 'visible': + return `Filter(new() { Visible = ${body === 'true' ? 'true' : 'false'} })`; case 'role': const attrs: string[] = []; if (isRegExp(options.name)) { diff --git a/packages/playwright-core/src/utils/isomorphic/locatorParser.ts b/packages/playwright-core/src/utils/isomorphic/locatorParser.ts index fff3d078fffd4..6dcbc1cbcc351 100644 --- a/packages/playwright-core/src/utils/isomorphic/locatorParser.ts +++ b/packages/playwright-core/src/utils/isomorphic/locatorParser.ts @@ -14,10 +14,11 @@ * limitations under the License. */ -import { escapeForAttributeSelector, escapeForTextSelector } from './stringUtils'; import { asLocators } from './locatorGenerators'; -import type { Language, Quote } from './locatorGenerators'; import { parseSelector } from './selectorParser'; +import { escapeForAttributeSelector, escapeForTextSelector } from './stringUtils'; + +import type { Language, Quote } from './locatorGenerators'; type TemplateParams = { quote: string, text: string }[]; function parseLocator(locator: string, testIdAttributeName: string): { selector: string, preferredQuote: Quote | undefined } { @@ -169,6 +170,8 @@ function transform(template: string, params: TemplateParams, testIdAttributeName .replace(/first(\(\))?/g, 'nth=0') .replace(/last(\(\))?/g, 'nth=-1') .replace(/nth\(([^)]+)\)/g, 'nth=$1') + .replace(/filter\(,?visible=true\)/g, 'visible=true') + .replace(/filter\(,?visible=false\)/g, 'visible=false') .replace(/filter\(,?hastext=([^)]+)\)/g, 'internal:has-text=$1') .replace(/filter\(,?hasnottext=([^)]+)\)/g, 'internal:has-not-text=$1') .replace(/filter\(,?has2=([^)]+)\)/g, 'internal:has=$1') diff --git a/packages/playwright-core/src/utils/manualPromise.ts b/packages/playwright-core/src/utils/isomorphic/manualPromise.ts similarity index 100% rename from packages/playwright-core/src/utils/manualPromise.ts rename to packages/playwright-core/src/utils/isomorphic/manualPromise.ts diff --git a/packages/playwright-core/src/utils/isomorphic/mimeType.ts b/packages/playwright-core/src/utils/isomorphic/mimeType.ts index 407d935281612..45ac92d645c45 100644 --- a/packages/playwright-core/src/utils/isomorphic/mimeType.ts +++ b/packages/playwright-core/src/utils/isomorphic/mimeType.ts @@ -1,14 +1,14 @@ /** * Copyright (c) Microsoft Corporation. * - * Licensed under the Apache License, Version 2.0 (the "License"); + * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * distributed under the License is distributed on an 'AS IS' BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. @@ -21,3 +21,426 @@ export function isJsonMimeType(mimeType: string) { export function isTextualMimeType(mimeType: string) { return !!mimeType.match(/^(text\/.*?|application\/(json|(x-)?javascript|xml.*?|ecmascript|graphql|x-www-form-urlencoded)|image\/svg(\+xml)?|application\/.*?(\+json|\+xml))(;\s*charset=.*)?$/); } +export function getMimeTypeForPath(path: string): string | null { + const dotIndex = path.lastIndexOf('.'); + if (dotIndex === -1) + return null; + const extension = path.substring(dotIndex + 1); + return types.get(extension) || null; +} + +const types: Map = new Map([ + ['ez', 'application/andrew-inset'], + ['aw', 'application/applixware'], + ['atom', 'application/atom+xml'], + ['atomcat', 'application/atomcat+xml'], + ['atomdeleted', 'application/atomdeleted+xml'], + ['atomsvc', 'application/atomsvc+xml'], + ['dwd', 'application/atsc-dwd+xml'], + ['held', 'application/atsc-held+xml'], + ['rsat', 'application/atsc-rsat+xml'], + ['bdoc', 'application/bdoc'], + ['xcs', 'application/calendar+xml'], + ['ccxml', 'application/ccxml+xml'], + ['cdfx', 'application/cdfx+xml'], + ['cdmia', 'application/cdmi-capability'], + ['cdmic', 'application/cdmi-container'], + ['cdmid', 'application/cdmi-domain'], + ['cdmio', 'application/cdmi-object'], + ['cdmiq', 'application/cdmi-queue'], + ['cu', 'application/cu-seeme'], + ['mpd', 'application/dash+xml'], + ['davmount', 'application/davmount+xml'], + ['dbk', 'application/docbook+xml'], + ['dssc', 'application/dssc+der'], + ['xdssc', 'application/dssc+xml'], + ['ecma', 'application/ecmascript'], + ['es', 'application/ecmascript'], + ['emma', 'application/emma+xml'], + ['emotionml', 'application/emotionml+xml'], + ['epub', 'application/epub+zip'], + ['exi', 'application/exi'], + ['exp', 'application/express'], + ['fdt', 'application/fdt+xml'], + ['pfr', 'application/font-tdpfr'], + ['geojson', 'application/geo+json'], + ['gml', 'application/gml+xml'], + ['gpx', 'application/gpx+xml'], + ['gxf', 'application/gxf'], + ['gz', 'application/gzip'], + ['hjson', 'application/hjson'], + ['stk', 'application/hyperstudio'], + ['ink', 'application/inkml+xml'], + ['inkml', 'application/inkml+xml'], + ['ipfix', 'application/ipfix'], + ['its', 'application/its+xml'], + ['ear', 'application/java-archive'], + ['jar', 'application/java-archive'], + ['war', 'application/java-archive'], + ['ser', 'application/java-serialized-object'], + ['class', 'application/java-vm'], + ['js', 'application/javascript'], + ['mjs', 'application/javascript'], + ['json', 'application/json'], + ['map', 'application/json'], + ['json5', 'application/json5'], + ['jsonml', 'application/jsonml+json'], + ['jsonld', 'application/ld+json'], + ['lgr', 'application/lgr+xml'], + ['lostxml', 'application/lost+xml'], + ['hqx', 'application/mac-binhex40'], + ['cpt', 'application/mac-compactpro'], + ['mads', 'application/mads+xml'], + ['webmanifest', 'application/manifest+json'], + ['mrc', 'application/marc'], + ['mrcx', 'application/marcxml+xml'], + ['ma', 'application/mathematica'], + ['mb', 'application/mathematica'], + ['nb', 'application/mathematica'], + ['mathml', 'application/mathml+xml'], + ['mbox', 'application/mbox'], + ['mscml', 'application/mediaservercontrol+xml'], + ['metalink', 'application/metalink+xml'], + ['meta4', 'application/metalink4+xml'], + ['mets', 'application/mets+xml'], + ['maei', 'application/mmt-aei+xml'], + ['musd', 'application/mmt-usd+xml'], + ['mods', 'application/mods+xml'], + ['m21', 'application/mp21'], + ['mp21', 'application/mp21'], + ['m4p', 'application/mp4'], + ['mp4s', 'application/mp4'], + ['doc', 'application/msword'], + ['dot', 'application/msword'], + ['mxf', 'application/mxf'], + ['nq', 'application/n-quads'], + ['nt', 'application/n-triples'], + ['cjs', 'application/node'], + ['bin', 'application/octet-stream'], + ['bpk', 'application/octet-stream'], + ['buffer', 'application/octet-stream'], + ['deb', 'application/octet-stream'], + ['deploy', 'application/octet-stream'], + ['dist', 'application/octet-stream'], + ['distz', 'application/octet-stream'], + ['dll', 'application/octet-stream'], + ['dmg', 'application/octet-stream'], + ['dms', 'application/octet-stream'], + ['dump', 'application/octet-stream'], + ['elc', 'application/octet-stream'], + ['exe', 'application/octet-stream'], + ['img', 'application/octet-stream'], + ['iso', 'application/octet-stream'], + ['lrf', 'application/octet-stream'], + ['mar', 'application/octet-stream'], + ['msi', 'application/octet-stream'], + ['msm', 'application/octet-stream'], + ['msp', 'application/octet-stream'], + ['pkg', 'application/octet-stream'], + ['so', 'application/octet-stream'], + ['oda', 'application/oda'], + ['opf', 'application/oebps-package+xml'], + ['ogx', 'application/ogg'], + ['omdoc', 'application/omdoc+xml'], + ['onepkg', 'application/onenote'], + ['onetmp', 'application/onenote'], + ['onetoc', 'application/onenote'], + ['onetoc2', 'application/onenote'], + ['oxps', 'application/oxps'], + ['relo', 'application/p2p-overlay+xml'], + ['xer', 'application/patch-ops-error+xml'], + ['pdf', 'application/pdf'], + ['pgp', 'application/pgp-encrypted'], + ['asc', 'application/pgp-signature'], + ['sig', 'application/pgp-signature'], + ['prf', 'application/pics-rules'], + ['p10', 'application/pkcs10'], + ['p7c', 'application/pkcs7-mime'], + ['p7m', 'application/pkcs7-mime'], + ['p7s', 'application/pkcs7-signature'], + ['p8', 'application/pkcs8'], + ['ac', 'application/pkix-attr-cert'], + ['cer', 'application/pkix-cert'], + ['crl', 'application/pkix-crl'], + ['pkipath', 'application/pkix-pkipath'], + ['pki', 'application/pkixcmp'], + ['pls', 'application/pls+xml'], + ['ai', 'application/postscript'], + ['eps', 'application/postscript'], + ['ps', 'application/postscript'], + ['provx', 'application/provenance+xml'], + ['pskcxml', 'application/pskc+xml'], + ['raml', 'application/raml+yaml'], + ['owl', 'application/rdf+xml'], + ['rdf', 'application/rdf+xml'], + ['rif', 'application/reginfo+xml'], + ['rnc', 'application/relax-ng-compact-syntax'], + ['rl', 'application/resource-lists+xml'], + ['rld', 'application/resource-lists-diff+xml'], + ['rs', 'application/rls-services+xml'], + ['rapd', 'application/route-apd+xml'], + ['sls', 'application/route-s-tsid+xml'], + ['rusd', 'application/route-usd+xml'], + ['gbr', 'application/rpki-ghostbusters'], + ['mft', 'application/rpki-manifest'], + ['roa', 'application/rpki-roa'], + ['rsd', 'application/rsd+xml'], + ['rss', 'application/rss+xml'], + ['rtf', 'application/rtf'], + ['sbml', 'application/sbml+xml'], + ['scq', 'application/scvp-cv-request'], + ['scs', 'application/scvp-cv-response'], + ['spq', 'application/scvp-vp-request'], + ['spp', 'application/scvp-vp-response'], + ['sdp', 'application/sdp'], + ['senmlx', 'application/senml+xml'], + ['sensmlx', 'application/sensml+xml'], + ['setpay', 'application/set-payment-initiation'], + ['setreg', 'application/set-registration-initiation'], + ['shf', 'application/shf+xml'], + ['sieve', 'application/sieve'], + ['siv', 'application/sieve'], + ['smi', 'application/smil+xml'], + ['smil', 'application/smil+xml'], + ['rq', 'application/sparql-query'], + ['srx', 'application/sparql-results+xml'], + ['gram', 'application/srgs'], + ['grxml', 'application/srgs+xml'], + ['sru', 'application/sru+xml'], + ['ssdl', 'application/ssdl+xml'], + ['ssml', 'application/ssml+xml'], + ['swidtag', 'application/swid+xml'], + ['tei', 'application/tei+xml'], + ['teicorpus', 'application/tei+xml'], + ['tfi', 'application/thraud+xml'], + ['tsd', 'application/timestamped-data'], + ['toml', 'application/toml'], + ['trig', 'application/trig'], + ['ttml', 'application/ttml+xml'], + ['ubj', 'application/ubjson'], + ['rsheet', 'application/urc-ressheet+xml'], + ['td', 'application/urc-targetdesc+xml'], + ['vxml', 'application/voicexml+xml'], + ['wasm', 'application/wasm'], + ['wgt', 'application/widget'], + ['hlp', 'application/winhlp'], + ['wsdl', 'application/wsdl+xml'], + ['wspolicy', 'application/wspolicy+xml'], + ['xaml', 'application/xaml+xml'], + ['xav', 'application/xcap-att+xml'], + ['xca', 'application/xcap-caps+xml'], + ['xdf', 'application/xcap-diff+xml'], + ['xel', 'application/xcap-el+xml'], + ['xns', 'application/xcap-ns+xml'], + ['xenc', 'application/xenc+xml'], + ['xht', 'application/xhtml+xml'], + ['xhtml', 'application/xhtml+xml'], + ['xlf', 'application/xliff+xml'], + ['rng', 'application/xml'], + ['xml', 'application/xml'], + ['xsd', 'application/xml'], + ['xsl', 'application/xml'], + ['dtd', 'application/xml-dtd'], + ['xop', 'application/xop+xml'], + ['xpl', 'application/xproc+xml'], + ['*xsl', 'application/xslt+xml'], + ['xslt', 'application/xslt+xml'], + ['xspf', 'application/xspf+xml'], + ['mxml', 'application/xv+xml'], + ['xhvml', 'application/xv+xml'], + ['xvm', 'application/xv+xml'], + ['xvml', 'application/xv+xml'], + ['yang', 'application/yang'], + ['yin', 'application/yin+xml'], + ['zip', 'application/zip'], + ['*3gpp', 'audio/3gpp'], + ['adp', 'audio/adpcm'], + ['amr', 'audio/amr'], + ['au', 'audio/basic'], + ['snd', 'audio/basic'], + ['kar', 'audio/midi'], + ['mid', 'audio/midi'], + ['midi', 'audio/midi'], + ['rmi', 'audio/midi'], + ['mxmf', 'audio/mobile-xmf'], + ['*mp3', 'audio/mp3'], + ['m4a', 'audio/mp4'], + ['mp4a', 'audio/mp4'], + ['m2a', 'audio/mpeg'], + ['m3a', 'audio/mpeg'], + ['mp2', 'audio/mpeg'], + ['mp2a', 'audio/mpeg'], + ['mp3', 'audio/mpeg'], + ['mpga', 'audio/mpeg'], + ['oga', 'audio/ogg'], + ['ogg', 'audio/ogg'], + ['opus', 'audio/ogg'], + ['spx', 'audio/ogg'], + ['s3m', 'audio/s3m'], + ['sil', 'audio/silk'], + ['wav', 'audio/wav'], + ['*wav', 'audio/wave'], + ['weba', 'audio/webm'], + ['xm', 'audio/xm'], + ['ttc', 'font/collection'], + ['otf', 'font/otf'], + ['ttf', 'font/ttf'], + ['woff', 'font/woff'], + ['woff2', 'font/woff2'], + ['exr', 'image/aces'], + ['apng', 'image/apng'], + ['avif', 'image/avif'], + ['bmp', 'image/bmp'], + ['cgm', 'image/cgm'], + ['drle', 'image/dicom-rle'], + ['emf', 'image/emf'], + ['fits', 'image/fits'], + ['g3', 'image/g3fax'], + ['gif', 'image/gif'], + ['heic', 'image/heic'], + ['heics', 'image/heic-sequence'], + ['heif', 'image/heif'], + ['heifs', 'image/heif-sequence'], + ['hej2', 'image/hej2k'], + ['hsj2', 'image/hsj2'], + ['ief', 'image/ief'], + ['jls', 'image/jls'], + ['jp2', 'image/jp2'], + ['jpg2', 'image/jp2'], + ['jpe', 'image/jpeg'], + ['jpeg', 'image/jpeg'], + ['jpg', 'image/jpeg'], + ['jph', 'image/jph'], + ['jhc', 'image/jphc'], + ['jpm', 'image/jpm'], + ['jpf', 'image/jpx'], + ['jpx', 'image/jpx'], + ['jxr', 'image/jxr'], + ['jxra', 'image/jxra'], + ['jxrs', 'image/jxrs'], + ['jxs', 'image/jxs'], + ['jxsc', 'image/jxsc'], + ['jxsi', 'image/jxsi'], + ['jxss', 'image/jxss'], + ['ktx', 'image/ktx'], + ['ktx2', 'image/ktx2'], + ['png', 'image/png'], + ['sgi', 'image/sgi'], + ['svg', 'image/svg+xml'], + ['svgz', 'image/svg+xml'], + ['t38', 'image/t38'], + ['tif', 'image/tiff'], + ['tiff', 'image/tiff'], + ['tfx', 'image/tiff-fx'], + ['webp', 'image/webp'], + ['wmf', 'image/wmf'], + ['disposition-notification', 'message/disposition-notification'], + ['u8msg', 'message/global'], + ['u8dsn', 'message/global-delivery-status'], + ['u8mdn', 'message/global-disposition-notification'], + ['u8hdr', 'message/global-headers'], + ['eml', 'message/rfc822'], + ['mime', 'message/rfc822'], + ['3mf', 'model/3mf'], + ['gltf', 'model/gltf+json'], + ['glb', 'model/gltf-binary'], + ['iges', 'model/iges'], + ['igs', 'model/iges'], + ['mesh', 'model/mesh'], + ['msh', 'model/mesh'], + ['silo', 'model/mesh'], + ['mtl', 'model/mtl'], + ['obj', 'model/obj'], + ['stpx', 'model/step+xml'], + ['stpz', 'model/step+zip'], + ['stpxz', 'model/step-xml+zip'], + ['stl', 'model/stl'], + ['vrml', 'model/vrml'], + ['wrl', 'model/vrml'], + ['*x3db', 'model/x3d+binary'], + ['x3dbz', 'model/x3d+binary'], + ['x3db', 'model/x3d+fastinfoset'], + ['*x3dv', 'model/x3d+vrml'], + ['x3dvz', 'model/x3d+vrml'], + ['x3d', 'model/x3d+xml'], + ['x3dz', 'model/x3d+xml'], + ['x3dv', 'model/x3d-vrml'], + ['appcache', 'text/cache-manifest'], + ['manifest', 'text/cache-manifest'], + ['ics', 'text/calendar'], + ['ifb', 'text/calendar'], + ['coffee', 'text/coffeescript'], + ['litcoffee', 'text/coffeescript'], + ['css', 'text/css'], + ['csv', 'text/csv'], + ['htm', 'text/html'], + ['html', 'text/html'], + ['shtml', 'text/html'], + ['jade', 'text/jade'], + ['jsx', 'text/jsx'], + ['less', 'text/less'], + ['markdown', 'text/markdown'], + ['md', 'text/markdown'], + ['mml', 'text/mathml'], + ['mdx', 'text/mdx'], + ['n3', 'text/n3'], + ['conf', 'text/plain'], + ['def', 'text/plain'], + ['in', 'text/plain'], + ['ini', 'text/plain'], + ['list', 'text/plain'], + ['log', 'text/plain'], + ['text', 'text/plain'], + ['txt', 'text/plain'], + ['rtx', 'text/richtext'], + ['*rtf', 'text/rtf'], + ['sgm', 'text/sgml'], + ['sgml', 'text/sgml'], + ['shex', 'text/shex'], + ['slim', 'text/slim'], + ['slm', 'text/slim'], + ['spdx', 'text/spdx'], + ['styl', 'text/stylus'], + ['stylus', 'text/stylus'], + ['tsv', 'text/tab-separated-values'], + ['man', 'text/troff'], + ['me', 'text/troff'], + ['ms', 'text/troff'], + ['roff', 'text/troff'], + ['t', 'text/troff'], + ['tr', 'text/troff'], + ['ttl', 'text/turtle'], + ['uri', 'text/uri-list'], + ['uris', 'text/uri-list'], + ['urls', 'text/uri-list'], + ['vcard', 'text/vcard'], + ['vtt', 'text/vtt'], + ['*xml', 'text/xml'], + ['yaml', 'text/yaml'], + ['yml', 'text/yaml'], + ['3gp', 'video/3gpp'], + ['3gpp', 'video/3gpp'], + ['3g2', 'video/3gpp2'], + ['h261', 'video/h261'], + ['h263', 'video/h263'], + ['h264', 'video/h264'], + ['m4s', 'video/iso.segment'], + ['jpgv', 'video/jpeg'], + ['jpm', 'video/jpm'], + ['jpgm', 'video/jpm'], + ['mj2', 'video/mj2'], + ['mjp2', 'video/mj2'], + ['ts', 'video/mp2t'], + ['mp4', 'video/mp4'], + ['mp4v', 'video/mp4'], + ['mpg4', 'video/mp4'], + ['m1v', 'video/mpeg'], + ['m2v', 'video/mpeg'], + ['mpe', 'video/mpeg'], + ['mpeg', 'video/mpeg'], + ['mpg', 'video/mpeg'], + ['ogv', 'video/ogg'], + ['mov', 'video/quicktime'], + ['qt', 'video/quicktime'], + ['webm', 'video/webm'] +]); diff --git a/packages/playwright-core/src/utils/multimap.ts b/packages/playwright-core/src/utils/isomorphic/multimap.ts similarity index 100% rename from packages/playwright-core/src/utils/multimap.ts rename to packages/playwright-core/src/utils/isomorphic/multimap.ts diff --git a/packages/playwright-core/src/utils/rtti.ts b/packages/playwright-core/src/utils/isomorphic/rtti.ts similarity index 86% rename from packages/playwright-core/src/utils/rtti.ts rename to packages/playwright-core/src/utils/isomorphic/rtti.ts index a18d3a450a75b..ffef6c1cad4ca 100644 --- a/packages/playwright-core/src/utils/rtti.ts +++ b/packages/playwright-core/src/utils/isomorphic/rtti.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -export { isString } from './isomorphic/stringUtils'; +export { isString } from './stringUtils'; export function isRegExp(obj: any): obj is RegExp { return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]'; @@ -27,5 +27,3 @@ export function isObject(obj: any): obj is NonNullable { export function isError(obj: any): obj is Error { return obj instanceof Error || (obj && Object.getPrototypeOf(obj)?.name === 'Error'); } - -export const isLikelyNpxGlobal = () => process.argv.length >= 2 && process.argv[1].includes('_npx'); diff --git a/packages/playwright-core/src/utils/isomorphic/selectorParser.ts b/packages/playwright-core/src/utils/isomorphic/selectorParser.ts index 64ba3c0c4df14..f37d1ef4c31d8 100644 --- a/packages/playwright-core/src/utils/isomorphic/selectorParser.ts +++ b/packages/playwright-core/src/utils/isomorphic/selectorParser.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -import type { CSSComplexSelectorList } from './cssParser'; import { InvalidSelectorError, parseCSS } from './cssParser'; + +import type { CSSComplexSelectorList } from './cssParser'; export { InvalidSelectorError, isInvalidSelectorError } from './cssParser'; export type NestedSelectorBody = { parsed: ParsedSelector, distance?: number }; diff --git a/packages/playwright-core/src/utils/semaphore.ts b/packages/playwright-core/src/utils/isomorphic/semaphore.ts similarity index 100% rename from packages/playwright-core/src/utils/semaphore.ts rename to packages/playwright-core/src/utils/isomorphic/semaphore.ts diff --git a/packages/playwright-core/src/utils/isomorphic/stackTrace.ts b/packages/playwright-core/src/utils/isomorphic/stackTrace.ts new file mode 100644 index 0000000000000..dca83848e9414 --- /dev/null +++ b/packages/playwright-core/src/utils/isomorphic/stackTrace.ts @@ -0,0 +1,201 @@ +/** + * The MIT License (MIT) + * Modifications copyright (c) Microsoft Corporation. + * + * Copyright (c) 2016-2023 Isaac Z. Schlueter i@izs.me, James Talmage james@talmage.io (github.com/jamestalmage), and + * Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +export type RawStack = string[]; + +export type StackFrame = { + file: string, + line: number, + column: number, + function?: string, +}; + +export function captureRawStack(): RawStack { + const stackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = 50; + const error = new Error(); + const stack = error.stack || ''; + Error.stackTraceLimit = stackTraceLimit; + return stack.split('\n'); +} + +export function parseStackFrame(text: string, pathSeparator: string, showInternalStackFrames: boolean): StackFrame | null { + const match = text && text.match(re); + if (!match) + return null; + + let fname = match[2]; + let file = match[7]; + if (!file) + return null; + if (!showInternalStackFrames && (file.startsWith('internal') || file.startsWith('node:'))) + return null; + + const line = match[8]; + const column = match[9]; + const closeParen = match[11] === ')'; + + const frame: StackFrame = { + file: '', + line: 0, + column: 0, + }; + + if (line) + frame.line = Number(line); + + if (column) + frame.column = Number(column); + + if (closeParen && file) { + // make sure parens are balanced + // if we have a file like "asdf) [as foo] (xyz.js", then odds are + // that the fname should be += " (asdf) [as foo]" and the file + // should be just "xyz.js" + // walk backwards from the end to find the last unbalanced ( + let closes = 0; + for (let i = file.length - 1; i > 0; i--) { + if (file.charAt(i) === ')') { + closes++; + } else if (file.charAt(i) === '(' && file.charAt(i - 1) === ' ') { + closes--; + if (closes === -1 && file.charAt(i - 1) === ' ') { + const before = file.slice(0, i - 1); + const after = file.slice(i + 1); + file = after; + fname += ` (${before}`; + break; + } + } + } + } + + if (fname) { + const methodMatch = fname.match(methodRe); + if (methodMatch) + fname = methodMatch[1]; + } + + if (file) { + if (file.startsWith('file://')) + file = fileURLToPath(file, pathSeparator); + frame.file = file; + } + + if (fname) + frame.function = fname; + + return frame; +} + +export function rewriteErrorMessage(e: E, newMessage: string): E { + const lines: string[] = (e.stack?.split('\n') || []).filter(l => l.startsWith(' at ')); + e.message = newMessage; + const errorTitle = `${e.name}: ${e.message}`; + if (lines.length) + e.stack = `${errorTitle}\n${lines.join('\n')}`; + return e; +} + +export function stringifyStackFrames(frames: StackFrame[]): string[] { + const stackLines: string[] = []; + for (const frame of frames) { + if (frame.function) + stackLines.push(` at ${frame.function} (${frame.file}:${frame.line}:${frame.column})`); + else + stackLines.push(` at ${frame.file}:${frame.line}:${frame.column}`); + } + return stackLines; +} + +export function splitErrorMessage(message: string): { name: string, message: string } { + const separationIdx = message.indexOf(':'); + return { + name: separationIdx !== -1 ? message.slice(0, separationIdx) : '', + message: separationIdx !== -1 && separationIdx + 2 <= message.length ? message.substring(separationIdx + 2) : message, + }; +} + +export function parseErrorStack(stack: string, pathSeparator: string, showInternalStackFrames: boolean = false): { + message: string; + stackLines: string[]; + location?: StackFrame; +} { + const lines = stack.split('\n'); + let firstStackLine = lines.findIndex(line => line.startsWith(' at ')); + if (firstStackLine === -1) + firstStackLine = lines.length; + const message = lines.slice(0, firstStackLine).join('\n'); + const stackLines = lines.slice(firstStackLine); + let location: StackFrame | undefined; + for (const line of stackLines) { + const frame = parseStackFrame(line, pathSeparator, showInternalStackFrames); + if (!frame || !frame.file) + continue; + if (belongsToNodeModules(frame.file, pathSeparator)) + continue; + location = { file: frame.file, column: frame.column || 0, line: frame.line || 0 }; + break; + } + return { message, stackLines, location }; +} + +function belongsToNodeModules(file: string, pathSeparator: string) { + return file.includes(`${pathSeparator}node_modules${pathSeparator}`); +} + +const re = new RegExp('^' + + // Sometimes we strip out the ' at' because it's noisy + '(?:\\s*at )?' + + // $1 = ctor if 'new' + '(?:(new) )?' + + // $2 = function name (can be literally anything) + // May contain method at the end as [as xyz] + '(?:(.*?) \\()?' + + // (eval at (file.js:1:1), + // $3 = eval origin + // $4:$5:$6 are eval file/line/col, but not normally reported + '(?:eval at ([^ ]+) \\((.+?):(\\d+):(\\d+)\\), )?' + + // file:line:col + // $7:$8:$9 + // $10 = 'native' if native + '(?:(.+?):(\\d+):(\\d+)|(native))' + + // maybe close the paren, then end + // if $11 is ), then we only allow balanced parens in the filename + // any imbalance is placed on the fname. This is a heuristic, and + // bound to be incorrect in some edge cases. The bet is that + // having weird characters in method names is more common than + // having weird characters in filenames, which seems reasonable. + '(\\)?)$' +); + +const methodRe = /^(.*?) \[as (.*?)\]$/; + +function fileURLToPath(fileUrl: string, pathSeparator: string): string { + if (!fileUrl.startsWith('file://')) + return fileUrl; + + let path = decodeURIComponent(fileUrl.slice(7)); + if (path.startsWith('/') && /^[a-zA-Z]:/.test(path.slice(1))) + path = path.slice(1); + + return path.replace(/\//g, pathSeparator); +} diff --git a/packages/playwright-core/src/utils/isomorphic/stringUtils.ts b/packages/playwright-core/src/utils/isomorphic/stringUtils.ts index ed81c9a0335ee..5a7602c97ae87 100644 --- a/packages/playwright-core/src/utils/isomorphic/stringUtils.ts +++ b/packages/playwright-core/src/utils/isomorphic/stringUtils.ts @@ -83,7 +83,7 @@ export function cacheNormalizedWhitespaces() { export function normalizeWhiteSpace(text: string): string { let result = normalizedWhitespaceCache?.get(text); if (result === undefined) { - result = text.replace(/\u200b/g, '').trim().replace(/\s+/g, ' '); + result = text.replace(/[\u200b\u00ad]/g, '').trim().replace(/\s+/g, ' '); normalizedWhitespaceCache?.set(text, result); } return result; diff --git a/packages/playwright-core/src/utils/isomorphic/time.ts b/packages/playwright-core/src/utils/isomorphic/time.ts new file mode 100644 index 0000000000000..981d45e2d2ad1 --- /dev/null +++ b/packages/playwright-core/src/utils/isomorphic/time.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function monotonicTime(): number { + return Math.floor(performance.now() * 1000) / 1000; +} diff --git a/packages/playwright-core/src/utils/timeoutRunner.ts b/packages/playwright-core/src/utils/isomorphic/timeoutRunner.ts similarity index 98% rename from packages/playwright-core/src/utils/timeoutRunner.ts rename to packages/playwright-core/src/utils/isomorphic/timeoutRunner.ts index 622019565a19b..e8016ddb49f67 100644 --- a/packages/playwright-core/src/utils/timeoutRunner.ts +++ b/packages/playwright-core/src/utils/isomorphic/timeoutRunner.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { monotonicTime } from './'; +import { monotonicTime } from './time'; export async function raceAgainstDeadline(cb: () => Promise, deadline: number): Promise<{ result: T, timedOut: false } | { timedOut: true }> { let timer: NodeJS.Timeout | undefined; diff --git a/packages/playwright-core/src/utils/isomorphic/traceUtils.ts b/packages/playwright-core/src/utils/isomorphic/traceUtils.ts index edb1e1c66081f..f077cc5c4b4a1 100644 --- a/packages/playwright-core/src/utils/isomorphic/traceUtils.ts +++ b/packages/playwright-core/src/utils/isomorphic/traceUtils.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { StackFrame } from '@protocol/channels'; +import type { ClientSideCallMetadata, StackFrame } from '@protocol/channels'; export type SerializedStackFrame = [number, number, number, string]; export type SerializedStack = [number, SerializedStackFrame[]]; @@ -33,3 +33,24 @@ export function parseClientSideCallMetadata(data: SerializedClientSideCallMetada } return result; } + +export function serializeClientSideCallMetadata(metadatas: ClientSideCallMetadata[]): SerializedClientSideCallMetadata { + const fileNames = new Map(); + const stacks: SerializedStack[] = []; + for (const m of metadatas) { + if (!m.stack || !m.stack.length) + continue; + const stack: SerializedStackFrame[] = []; + for (const frame of m.stack) { + let ordinal = fileNames.get(frame.file); + if (typeof ordinal !== 'number') { + ordinal = fileNames.size; + fileNames.set(frame.file, ordinal); + } + const stackFrame: SerializedStackFrame = [ordinal, frame.line || 0, frame.column || 0, frame.function || '']; + stack.push(stackFrame); + } + stacks.push([m.id, stack]); + } + return { files: [...fileNames.keys()], stacks }; +} diff --git a/packages/playwright-core/src/common/types.ts b/packages/playwright-core/src/utils/isomorphic/types.ts similarity index 100% rename from packages/playwright-core/src/common/types.ts rename to packages/playwright-core/src/utils/isomorphic/types.ts diff --git a/packages/playwright-core/src/utils/stackTrace.ts b/packages/playwright-core/src/utils/stackTrace.ts deleted file mode 100644 index eba52a30f22ef..0000000000000 --- a/packages/playwright-core/src/utils/stackTrace.ts +++ /dev/null @@ -1,158 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import path from 'path'; -import { parseStackTraceLine } from '../utilsBundle'; -import type { StackFrame } from '@protocol/channels'; -import { colors } from '../utilsBundle'; -import { findRepeatedSubsequences } from './sequence'; - -export function rewriteErrorMessage(e: E, newMessage: string): E { - const lines: string[] = (e.stack?.split('\n') || []).filter(l => l.startsWith(' at ')); - e.message = newMessage; - const errorTitle = `${e.name}: ${e.message}`; - if (lines.length) - e.stack = `${errorTitle}\n${lines.join('\n')}`; - return e; -} - -const CORE_DIR = path.resolve(__dirname, '..', '..'); - -const internalStackPrefixes = [ - CORE_DIR, -]; -export const addInternalStackPrefix = (prefix: string) => internalStackPrefixes.push(prefix); - -export type RawStack = string[]; - -export function captureRawStack(): RawStack { - const stackTraceLimit = Error.stackTraceLimit; - Error.stackTraceLimit = 50; - const error = new Error(); - const stack = error.stack || ''; - Error.stackTraceLimit = stackTraceLimit; - return stack.split('\n'); -} - -export function captureLibraryStackTrace(): { frames: StackFrame[], apiName: string } { - const stack = captureRawStack(); - - type ParsedFrame = { - frame: StackFrame; - frameText: string; - isPlaywrightLibrary: boolean; - }; - let parsedFrames = stack.map(line => { - const frame = parseStackTraceLine(line); - if (!frame || !frame.file) - return null; - const isPlaywrightLibrary = frame.file.startsWith(CORE_DIR); - const parsed: ParsedFrame = { - frame, - frameText: line, - isPlaywrightLibrary - }; - return parsed; - }).filter(Boolean) as ParsedFrame[]; - - let apiName = ''; - - // Deepest transition between non-client code calling into client - // code is the api entry. - for (let i = 0; i < parsedFrames.length - 1; i++) { - const parsedFrame = parsedFrames[i]; - if (parsedFrame.isPlaywrightLibrary && !parsedFrames[i + 1].isPlaywrightLibrary) { - apiName = apiName || normalizeAPIName(parsedFrame.frame.function); - break; - } - } - - function normalizeAPIName(name?: string): string { - if (!name) - return ''; - const match = name.match(/(API|JS|CDP|[A-Z])(.*)/); - if (!match) - return name; - return match[1].toLowerCase() + match[2]; - } - - // This is for the inspector so that it did not include the test runner stack frames. - parsedFrames = parsedFrames.filter(f => { - if (process.env.PWDEBUGIMPL) - return true; - if (internalStackPrefixes.some(prefix => f.frame.file.startsWith(prefix))) - return false; - return true; - }); - - return { - frames: parsedFrames.map(p => p.frame), - apiName - }; -} - -export function stringifyStackFrames(frames: StackFrame[]): string[] { - const stackLines: string[] = []; - for (const frame of frames) { - if (frame.function) - stackLines.push(` at ${frame.function} (${frame.file}:${frame.line}:${frame.column})`); - else - stackLines.push(` at ${frame.file}:${frame.line}:${frame.column}`); - } - return stackLines; -} - -export function captureLibraryStackText() { - const parsed = captureLibraryStackTrace(); - return stringifyStackFrames(parsed.frames).join('\n'); -} - -export function splitErrorMessage(message: string): { name: string, message: string } { - const separationIdx = message.indexOf(':'); - return { - name: separationIdx !== -1 ? message.slice(0, separationIdx) : '', - message: separationIdx !== -1 && separationIdx + 2 <= message.length ? message.substring(separationIdx + 2) : message, - }; -} - -export function formatCallLog(log: string[] | undefined): string { - if (!log || !log.some(l => !!l)) - return ''; - return ` -Call log: -${colors.dim(log.join('\n'))} -`; -} - -export function compressCallLog(log: string[]): string[] { - const lines: string[] = []; - - for (const block of findRepeatedSubsequences(log)) { - for (let i = 0; i < block.sequence.length; i++) { - const line = block.sequence[i]; - const leadingWhitespace = line.match(/^\s*/); - const whitespacePrefix = ' ' + leadingWhitespace?.[0] || ''; - const countPrefix = `${block.count} × `; - if (block.count > 1 && i === 0) - lines.push(whitespacePrefix + countPrefix + line.trim()); - else if (block.count > 1) - lines.push(whitespacePrefix + ' '.repeat(countPrefix.length - 2) + '- ' + line.trim()); - else - lines.push(whitespacePrefix + '- ' + line.trim()); - } - } - return lines; -} diff --git a/packages/playwright-core/src/utils/time.ts b/packages/playwright-core/src/utils/time.ts deleted file mode 100644 index d00ee62e82fc5..0000000000000 --- a/packages/playwright-core/src/utils/time.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// The `process.hrtime()` returns a time from some arbitrary -// date in the past; on certain systems, this is the time from the system boot. -// The `monotonicTime()` converts this to milliseconds. -// -// For a Linux server with uptime of 36 days, the `monotonicTime()` value -// will be 36 * 86400 * 1000 = 3_110_400_000, which is larger than -// the maximum value that `setTimeout` accepts as an argument: 2_147_483_647. -// -// To make the `monotonicTime()` a reasonable value, we anchor -// it to the time of the first import of this utility. -const initialTime = process.hrtime(); - -export function monotonicTime(): number { - const [seconds, nanoseconds] = process.hrtime(initialTime); - return seconds * 1000 + (nanoseconds / 1000 | 0) / 1000; -} diff --git a/packages/playwright-core/src/utils/traceUtils.ts b/packages/playwright-core/src/utils/traceUtils.ts deleted file mode 100644 index d0090b3665590..0000000000000 --- a/packages/playwright-core/src/utils/traceUtils.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ClientSideCallMetadata } from '@protocol/channels'; -import type { SerializedClientSideCallMetadata, SerializedStack, SerializedStackFrame } from './isomorphic/traceUtils'; - -export function serializeClientSideCallMetadata(metadatas: ClientSideCallMetadata[]): SerializedClientSideCallMetadata { - const fileNames = new Map(); - const stacks: SerializedStack[] = []; - for (const m of metadatas) { - if (!m.stack || !m.stack.length) - continue; - const stack: SerializedStackFrame[] = []; - for (const frame of m.stack) { - let ordinal = fileNames.get(frame.file); - if (typeof ordinal !== 'number') { - ordinal = fileNames.size; - fileNames.set(frame.file, ordinal); - } - const stackFrame: SerializedStackFrame = [ordinal, frame.line || 0, frame.column || 0, frame.function || '']; - stack.push(stackFrame); - } - stacks.push([m.id, stack]); - } - return { files: [...fileNames.keys()], stacks }; -} diff --git a/packages/playwright-core/src/utilsBundle.ts b/packages/playwright-core/src/utilsBundle.ts index fba52c05a831f..41cccd1f57263 100644 --- a/packages/playwright-core/src/utilsBundle.ts +++ b/packages/playwright-core/src/utilsBundle.ts @@ -14,9 +14,6 @@ * limitations under the License. */ -import url from 'url'; -import path from 'path'; - export const colors: typeof import('../bundles/utils/node_modules/colors/safe') = require('./utilsBundleImpl').colors; export const debug: typeof import('../bundles/utils/node_modules/@types/debug') = require('./utilsBundleImpl').debug; export const diff: typeof import('../bundles/utils/node_modules/@types/diff') = require('./utilsBundleImpl').diff; @@ -33,35 +30,13 @@ export const program: typeof import('../bundles/utils/node_modules/commander').p export const progress: typeof import('../bundles/utils/node_modules/@types/progress') = require('./utilsBundleImpl').progress; export const SocksProxyAgent: typeof import('../bundles/utils/node_modules/socks-proxy-agent').SocksProxyAgent = require('./utilsBundleImpl').SocksProxyAgent; export const yaml: typeof import('../bundles/utils/node_modules/yaml') = require('./utilsBundleImpl').yaml; -export type { Scalar as YAMLScalar, YAMLSeq, YAMLMap, YAMLError, Range as YAMLRange } from '../bundles/utils/node_modules/yaml'; +export type { Range as YAMLRange, Scalar as YAMLScalar, YAMLError, YAMLMap, YAMLSeq } from '../bundles/utils/node_modules/yaml'; export const ws: typeof import('../bundles/utils/node_modules/@types/ws') = require('./utilsBundleImpl').ws; export const wsServer: typeof import('../bundles/utils/node_modules/@types/ws').WebSocketServer = require('./utilsBundleImpl').wsServer; export const wsReceiver = require('./utilsBundleImpl').wsReceiver; export const wsSender = require('./utilsBundleImpl').wsSender; export type { Command } from '../bundles/utils/node_modules/commander'; -export type { WebSocket, WebSocketServer, RawData as WebSocketRawData, EventEmitter as WebSocketEventEmitter } from '../bundles/utils/node_modules/@types/ws'; -import type { StackFrame } from '@protocol/channels'; - -const StackUtils: typeof import('../bundles/utils/node_modules/@types/stack-utils') = require('./utilsBundleImpl').StackUtils; -const stackUtils = new StackUtils({ internals: StackUtils.nodeInternals() }); - -export function parseStackTraceLine(line: string): StackFrame | null { - const frame = stackUtils.parseLine(line); - if (!frame) - return null; - if (!process.env.PWDEBUGIMPL && (frame.file?.startsWith('internal') || frame.file?.startsWith('node:'))) - return null; - if (!frame.file) - return null; - // ESM files return file:// URLs, see here: https://github.com/tapjs/stack-utils/issues/60 - const file = frame.file.startsWith('file://') ? url.fileURLToPath(frame.file) : path.resolve(process.cwd(), frame.file); - return { - file, - line: frame.line || 0, - column: frame.column || 0, - function: frame.function, - }; -} +export type { EventEmitter as WebSocketEventEmitter, RawData as WebSocketRawData, WebSocket, WebSocketServer } from '../bundles/utils/node_modules/@types/ws'; export function ms(ms: number): string { if (!isFinite(ms)) diff --git a/packages/playwright-core/src/zipBundle.ts b/packages/playwright-core/src/zipBundle.ts index 9c275873a8d1e..22569758b688b 100644 --- a/packages/playwright-core/src/zipBundle.ts +++ b/packages/playwright-core/src/zipBundle.ts @@ -17,5 +17,5 @@ export const yazl: typeof import('../bundles/zip/node_modules/@types/yazl') = require('./zipBundleImpl').yazl; export type { ZipFile } from '../bundles/zip/node_modules/@types/yazl'; export const yauzl: typeof import('../bundles/zip/node_modules/@types/yauzl') = require('./zipBundleImpl').yauzl; -export type { ZipFile as UnzipFile, Entry } from '../bundles/zip/node_modules/@types/yauzl'; +export type { Entry, ZipFile as UnzipFile } from '../bundles/zip/node_modules/@types/yauzl'; export const extract: typeof import('../bundles/zip/node_modules/extract-zip') = require('./zipBundleImpl').extract; diff --git a/packages/playwright-core/types/protocol.d.ts b/packages/playwright-core/types/protocol.d.ts index fa1d6121f9af7..ebfd237d45827 100644 --- a/packages/playwright-core/types/protocol.d.ts +++ b/packages/playwright-core/types/protocol.d.ts @@ -952,7 +952,7 @@ Should be updated alongside RequestIdTokenStatus in third_party/blink/public/mojom/devtools/inspector_issue.mojom to include all cases except for success. */ - export type FederatedAuthRequestIssueReason = "ShouldEmbargo"|"TooManyRequests"|"WellKnownHttpNotFound"|"WellKnownNoResponse"|"WellKnownInvalidResponse"|"WellKnownListEmpty"|"WellKnownInvalidContentType"|"ConfigNotInWellKnown"|"WellKnownTooBig"|"ConfigHttpNotFound"|"ConfigNoResponse"|"ConfigInvalidResponse"|"ConfigInvalidContentType"|"ClientMetadataHttpNotFound"|"ClientMetadataNoResponse"|"ClientMetadataInvalidResponse"|"ClientMetadataInvalidContentType"|"IdpNotPotentiallyTrustworthy"|"DisabledInSettings"|"DisabledInFlags"|"ErrorFetchingSignin"|"InvalidSigninResponse"|"AccountsHttpNotFound"|"AccountsNoResponse"|"AccountsInvalidResponse"|"AccountsListEmpty"|"AccountsInvalidContentType"|"IdTokenHttpNotFound"|"IdTokenNoResponse"|"IdTokenInvalidResponse"|"IdTokenIdpErrorResponse"|"IdTokenCrossSiteIdpErrorResponse"|"IdTokenInvalidRequest"|"IdTokenInvalidContentType"|"ErrorIdToken"|"Canceled"|"RpPageNotVisible"|"SilentMediationFailure"|"ThirdPartyCookiesBlocked"|"NotSignedInWithIdp"|"MissingTransientUserActivation"|"ReplacedByActiveMode"|"InvalidFieldsSpecified"|"RelyingPartyOriginIsOpaque"|"TypeNotMatching"; + export type FederatedAuthRequestIssueReason = "ShouldEmbargo"|"TooManyRequests"|"WellKnownHttpNotFound"|"WellKnownNoResponse"|"WellKnownInvalidResponse"|"WellKnownListEmpty"|"WellKnownInvalidContentType"|"ConfigNotInWellKnown"|"WellKnownTooBig"|"ConfigHttpNotFound"|"ConfigNoResponse"|"ConfigInvalidResponse"|"ConfigInvalidContentType"|"ClientMetadataHttpNotFound"|"ClientMetadataNoResponse"|"ClientMetadataInvalidResponse"|"ClientMetadataInvalidContentType"|"IdpNotPotentiallyTrustworthy"|"DisabledInSettings"|"DisabledInFlags"|"ErrorFetchingSignin"|"InvalidSigninResponse"|"AccountsHttpNotFound"|"AccountsNoResponse"|"AccountsInvalidResponse"|"AccountsListEmpty"|"AccountsInvalidContentType"|"IdTokenHttpNotFound"|"IdTokenNoResponse"|"IdTokenInvalidResponse"|"IdTokenIdpErrorResponse"|"IdTokenCrossSiteIdpErrorResponse"|"IdTokenInvalidRequest"|"IdTokenInvalidContentType"|"ErrorIdToken"|"Canceled"|"RpPageNotVisible"|"SilentMediationFailure"|"ThirdPartyCookiesBlocked"|"NotSignedInWithIdp"|"MissingTransientUserActivation"|"ReplacedByActiveMode"|"InvalidFieldsSpecified"|"RelyingPartyOriginIsOpaque"|"TypeNotMatching"|"UiDismissedNoEmbargo"; export interface FederatedAuthUserInfoRequestIssueDetails { federatedAuthUserInfoRequestIssueReason: FederatedAuthUserInfoRequestIssueReason; } @@ -983,7 +983,7 @@ features, encourage the use of new ones, and provide general guidance. } export type SelectElementAccessibilityIssueReason = "DisallowedSelectChild"|"DisallowedOptGroupChild"|"NonPhrasingContentOptionChild"|"InteractiveContentOptionChild"|"InteractiveContentLegendChild"; /** - * This isue warns about errors in the select element content model. + * This issue warns about errors in the select element content model. */ export interface SelectElementAccessibilityIssueDetails { nodeId: DOM.BackendNodeId; @@ -1187,6 +1187,19 @@ flag is set. */ id: string; } + /** + * Uninstalls an unpacked extension (others not supported) from the profile. +Available if the client is connected using the --remote-debugging-pipe flag +and the --enable-unsafe-extension-debugging. + */ + export type uninstallParameters = { + /** + * Extension id. + */ + id: string; + } + export type uninstallReturnValue = { + } /** * Gets data from extension storage in the given `storageArea`. If `keys` is specified, these are used to filter the result. @@ -2913,6 +2926,13 @@ incorrect results if the declaration contains a var() for example. * Identifier of the frame where "via-inspector" stylesheet should be created. */ frameId: Page.FrameId; + /** + * If true, creates a new stylesheet for every call. If false, +returns a stylesheet previously created by a call with force=false +for the frame's document if it exists or creates a new stylesheet +(default: false). + */ + force?: boolean; } export type createStyleSheetReturnValue = { /** @@ -5974,81 +5994,6 @@ The final text color opacity is computed based on the opacity of all overlapping } } - export module Database { - /** - * Unique identifier of Database object. - */ - export type DatabaseId = string; - /** - * Database object. - */ - export interface Database { - /** - * Database ID. - */ - id: DatabaseId; - /** - * Database domain. - */ - domain: string; - /** - * Database name. - */ - name: string; - /** - * Database version. - */ - version: string; - } - /** - * Database error. - */ - export interface Error { - /** - * Error message. - */ - message: string; - /** - * Error code. - */ - code: number; - } - - export type addDatabasePayload = { - database: Database; - } - - /** - * Disables database tracking, prevents database events from being sent to the client. - */ - export type disableParameters = { - } - export type disableReturnValue = { - } - /** - * Enables database tracking, database events will now be delivered to the client. - */ - export type enableParameters = { - } - export type enableReturnValue = { - } - export type executeSQLParameters = { - databaseId: DatabaseId; - query: string; - } - export type executeSQLReturnValue = { - columnNames?: string[]; - values?: any[]; - sqlError?: Error; - } - export type getDatabaseTableNamesParameters = { - databaseId: DatabaseId; - } - export type getDatabaseTableNamesReturnValue = { - tableNames: string[]; - } - } - export module DeviceOrientation { @@ -9126,7 +9071,7 @@ This is a temporary ability and it will be removed in the future. /** * Types of reasons why a cookie should have been blocked by 3PCD but is exempted for the request. */ - export type CookieExemptionReason = "None"|"UserSetting"|"TPCDMetadata"|"TPCDDeprecationTrial"|"TopLevelTPCDDeprecationTrial"|"TPCDHeuristics"|"EnterprisePolicy"|"StorageAccess"|"TopLevelStorageAccess"|"Scheme"; + export type CookieExemptionReason = "None"|"UserSetting"|"TPCDMetadata"|"TPCDDeprecationTrial"|"TopLevelTPCDDeprecationTrial"|"TPCDHeuristics"|"EnterprisePolicy"|"StorageAccess"|"TopLevelStorageAccess"|"Scheme"|"SameSiteNoneCookiesInSandbox"; /** * A cookie which was not stored from a response with the corresponding reason. */ @@ -11702,7 +11647,7 @@ as an ad. * All Permissions Policy features. This enum should match the one defined in third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5. */ - export type PermissionsPolicyFeature = "accelerometer"|"all-screens-capture"|"ambient-light-sensor"|"attribution-reporting"|"autoplay"|"bluetooth"|"browsing-topics"|"camera"|"captured-surface-control"|"ch-dpr"|"ch-device-memory"|"ch-downlink"|"ch-ect"|"ch-prefers-color-scheme"|"ch-prefers-reduced-motion"|"ch-prefers-reduced-transparency"|"ch-rtt"|"ch-save-data"|"ch-ua"|"ch-ua-arch"|"ch-ua-bitness"|"ch-ua-platform"|"ch-ua-model"|"ch-ua-mobile"|"ch-ua-form-factors"|"ch-ua-full-version"|"ch-ua-full-version-list"|"ch-ua-platform-version"|"ch-ua-wow64"|"ch-viewport-height"|"ch-viewport-width"|"ch-width"|"clipboard-read"|"clipboard-write"|"compute-pressure"|"controlled-frame"|"cross-origin-isolated"|"deferred-fetch"|"deferred-fetch-minimal"|"digital-credentials-get"|"direct-sockets"|"direct-sockets-private"|"display-capture"|"document-domain"|"encrypted-media"|"execution-while-out-of-viewport"|"execution-while-not-rendered"|"fenced-unpartitioned-storage-read"|"focus-without-user-activation"|"fullscreen"|"frobulate"|"gamepad"|"geolocation"|"gyroscope"|"hid"|"identity-credentials-get"|"idle-detection"|"interest-cohort"|"join-ad-interest-group"|"keyboard-map"|"local-fonts"|"magnetometer"|"media-playback-while-not-visible"|"microphone"|"midi"|"otp-credentials"|"payment"|"picture-in-picture"|"popins"|"private-aggregation"|"private-state-token-issuance"|"private-state-token-redemption"|"publickey-credentials-create"|"publickey-credentials-get"|"run-ad-auction"|"screen-wake-lock"|"serial"|"shared-autofill"|"shared-storage"|"shared-storage-select-url"|"smart-card"|"speaker-selection"|"storage-access"|"sub-apps"|"sync-xhr"|"unload"|"usb"|"usb-unrestricted"|"vertical-scroll"|"web-app-installation"|"web-printing"|"web-share"|"window-management"|"xr-spatial-tracking"; + export type PermissionsPolicyFeature = "accelerometer"|"all-screens-capture"|"ambient-light-sensor"|"attribution-reporting"|"autoplay"|"bluetooth"|"browsing-topics"|"camera"|"captured-surface-control"|"ch-dpr"|"ch-device-memory"|"ch-downlink"|"ch-ect"|"ch-prefers-color-scheme"|"ch-prefers-reduced-motion"|"ch-prefers-reduced-transparency"|"ch-rtt"|"ch-save-data"|"ch-ua"|"ch-ua-arch"|"ch-ua-bitness"|"ch-ua-high-entropy-values"|"ch-ua-platform"|"ch-ua-model"|"ch-ua-mobile"|"ch-ua-form-factors"|"ch-ua-full-version"|"ch-ua-full-version-list"|"ch-ua-platform-version"|"ch-ua-wow64"|"ch-viewport-height"|"ch-viewport-width"|"ch-width"|"clipboard-read"|"clipboard-write"|"compute-pressure"|"controlled-frame"|"cross-origin-isolated"|"deferred-fetch"|"deferred-fetch-minimal"|"digital-credentials-get"|"direct-sockets"|"direct-sockets-private"|"display-capture"|"document-domain"|"encrypted-media"|"execution-while-out-of-viewport"|"execution-while-not-rendered"|"fenced-unpartitioned-storage-read"|"focus-without-user-activation"|"fullscreen"|"frobulate"|"gamepad"|"geolocation"|"gyroscope"|"hid"|"identity-credentials-get"|"idle-detection"|"interest-cohort"|"join-ad-interest-group"|"keyboard-map"|"local-fonts"|"magnetometer"|"media-playback-while-not-visible"|"microphone"|"midi"|"otp-credentials"|"payment"|"picture-in-picture"|"popins"|"private-aggregation"|"private-state-token-issuance"|"private-state-token-redemption"|"publickey-credentials-create"|"publickey-credentials-get"|"run-ad-auction"|"screen-wake-lock"|"serial"|"shared-autofill"|"shared-storage"|"shared-storage-select-url"|"smart-card"|"speaker-selection"|"storage-access"|"sub-apps"|"sync-xhr"|"unload"|"usb"|"usb-unrestricted"|"vertical-scroll"|"web-app-installation"|"web-printing"|"web-share"|"window-management"|"xr-spatial-tracking"; /** * Reason for a permissions policy feature to be disabled. */ @@ -12431,6 +12376,33 @@ subtree is actually detached. frame: Frame; } export type frameResizedPayload = void; + /** + * Fired when a navigation starts. This event is fired for both +renderer-initiated and browser-initiated navigations. For renderer-initiated +navigations, the event is fired after `frameRequestedNavigation`. +Navigation may still be cancelled after the event is issued. Multiple events +can be fired for a single navigation, for example, when a same-document +navigation becomes a cross-document navigation (such as in the case of a +frameset). + */ + export type frameStartedNavigatingPayload = { + /** + * ID of the frame that is being navigated. + */ + frameId: FrameId; + /** + * The URL the navigation started with. The final URL can be different. + */ + url: string; + /** + * Loader identifier. Even though it is present in case of same-document +navigation, the previously committed loaderId would not change unless +the navigation changes from a same-document to a cross-document +navigation. + */ + loaderId: Network.LoaderId; + navigationType: "reload"|"reloadBypassingCache"|"restore"|"restoreWithPost"|"historySameDocument"|"historyDifferentDocument"|"sameDocument"|"differentDocument"; + } /** * Fired when a renderer-initiated navigation is requested. Navigation may still be cancelled after the event is issued. @@ -14281,7 +14253,7 @@ For cached script it is the last time the cache entry was validated. /** * Enum of possible storage types. */ - export type StorageType = "appcache"|"cookies"|"file_systems"|"indexeddb"|"local_storage"|"shader_cache"|"websql"|"service_workers"|"cache_storage"|"interest_groups"|"shared_storage"|"storage_buckets"|"all"|"other"; + export type StorageType = "cookies"|"file_systems"|"indexeddb"|"local_storage"|"shader_cache"|"websql"|"service_workers"|"cache_storage"|"interest_groups"|"shared_storage"|"storage_buckets"|"all"|"other"; /** * Usage for a storage type. */ @@ -15193,6 +15165,28 @@ session. The effective Related Website Sets will not change during a browser ses export type getRelatedWebsiteSetsReturnValue = { sets: RelatedWebsiteSet[]; } + /** + * Returns the list of URLs from a page and its embedded resources that match +existing grace period URL pattern rules. +https://developers.google.com/privacy-sandbox/cookies/temporary-exceptions/grace-period + */ + export type getAffectedUrlsForThirdPartyCookieMetadataParameters = { + /** + * The URL of the page currently being visited. + */ + firstPartyUrl: string; + /** + * The list of embedded resource URLs from the page. + */ + thirdPartyUrls: string[]; + } + export type getAffectedUrlsForThirdPartyCookieMetadataReturnValue = { + /** + * Array of matching URLs. If there is a primary pattern match for the first- +party URL, only the first-party URL is returned in the array. + */ + matchedUrls: string[]; + } } /** @@ -15485,6 +15479,10 @@ If filter is not specified, the one assumed is host: string; port: number; } + /** + * The state of the target window. + */ + export type WindowState = "normal"|"minimized"|"maximized"|"fullscreen"; /** * Issued when attached to target because of auto-attach or `attachToTarget` command. @@ -15677,37 +15675,42 @@ Parts of the URL other than those constituting origin are ignored. */ url: string; /** - * Frame left origin in DIP (headless chrome only). + * Frame left origin in DIP (requires newWindow to be true or headless shell). */ left?: number; /** - * Frame top origin in DIP (headless chrome only). + * Frame top origin in DIP (requires newWindow to be true or headless shell). */ top?: number; /** - * Frame width in DIP (headless chrome only). + * Frame width in DIP (requires newWindow to be true or headless shell). */ width?: number; /** - * Frame height in DIP (headless chrome only). + * Frame height in DIP (requires newWindow to be true or headless shell). */ height?: number; + /** + * Frame window state (requires newWindow to be true or headless shell). +Default is normal. + */ + windowState?: WindowState; /** * The browser context to create the page in. */ browserContextId?: Browser.BrowserContextID; /** - * Whether BeginFrames for this target will be controlled via DevTools (headless chrome only, + * Whether BeginFrames for this target will be controlled via DevTools (headless shell only, not supported on MacOS yet, false by default). */ enableBeginFrameControl?: boolean; /** - * Whether to create a new Window or Tab (chrome-only, false by default). + * Whether to create a new Window or Tab (false by default, not supported by headless shell). */ newWindow?: boolean; /** - * Whether to create the target in background or foreground (chrome-only, -false by default). + * Whether to create the target in background or foreground (false by default, not supported +by headless shell). */ background?: boolean; /** @@ -18012,9 +18015,20 @@ variables as its properties. */ externalURL?: string; } + export interface ResolvedBreakpoint { + /** + * Breakpoint unique identifier. + */ + breakpointId: BreakpointId; + /** + * Actual breakpoint location. + */ + location: Location; + } /** * Fired when breakpoint is resolved to an actual script and location. +Deprecated in favor of `resolvedBreakpoints` in the `scriptParsed` event. */ export type breakpointResolvedPayload = { /** @@ -18225,6 +18239,12 @@ scripts upon enabling debugger. * The name the embedder supplied for this script. */ embedderName?: string; + /** + * The list of set breakpoints in this script if calls to `setBreakpointByUrl` +matches this script's URL or hash. Clients that use this list can ignore the +`breakpointResolved` event. They are equivalent. + */ + resolvedBreakpoints?: ResolvedBreakpoint[]; } /** @@ -20150,13 +20170,21 @@ It is the total usage of the corresponding isolate not scoped to a particular Ru } export type getHeapUsageReturnValue = { /** - * Used heap size in bytes. + * Used JavaScript heap size in bytes. */ usedSize: number; /** - * Allocated heap size in bytes. + * Allocated JavaScript heap size in bytes. */ totalSize: number; + /** + * Used size in bytes in the embedder's garbage-collected heap. + */ + embedderHeapUsedSize: number; + /** + * Size in bytes of backing storage for array buffers and external strings. + */ + backingStorageSize: number; } /** * Returns properties of a given object. Object group of the result is inherited from the target @@ -20472,7 +20500,6 @@ Error was thrown. "DOMStorage.domStorageItemRemoved": DOMStorage.domStorageItemRemovedPayload; "DOMStorage.domStorageItemUpdated": DOMStorage.domStorageItemUpdatedPayload; "DOMStorage.domStorageItemsCleared": DOMStorage.domStorageItemsClearedPayload; - "Database.addDatabase": Database.addDatabasePayload; "Emulation.virtualTimeBudgetExpired": Emulation.virtualTimeBudgetExpiredPayload; "Input.dragIntercepted": Input.dragInterceptedPayload; "Inspector.detached": Inspector.detachedPayload; @@ -20526,6 +20553,7 @@ Error was thrown. "Page.frameNavigated": Page.frameNavigatedPayload; "Page.documentOpened": Page.documentOpenedPayload; "Page.frameResized": Page.frameResizedPayload; + "Page.frameStartedNavigating": Page.frameStartedNavigatingPayload; "Page.frameRequestedNavigation": Page.frameRequestedNavigationPayload; "Page.frameScheduledNavigation": Page.frameScheduledNavigationPayload; "Page.frameStartedLoading": Page.frameStartedLoadingPayload; @@ -20656,6 +20684,7 @@ Error was thrown. "Audits.checkContrast": Audits.checkContrastParameters; "Audits.checkFormsIssues": Audits.checkFormsIssuesParameters; "Extensions.loadUnpacked": Extensions.loadUnpackedParameters; + "Extensions.uninstall": Extensions.uninstallParameters; "Extensions.getStorageItems": Extensions.getStorageItemsParameters; "Extensions.removeStorageItems": Extensions.removeStorageItemsParameters; "Extensions.clearStorageItems": Extensions.clearStorageItemsParameters; @@ -20808,10 +20837,6 @@ Error was thrown. "DOMStorage.getDOMStorageItems": DOMStorage.getDOMStorageItemsParameters; "DOMStorage.removeDOMStorageItem": DOMStorage.removeDOMStorageItemParameters; "DOMStorage.setDOMStorageItem": DOMStorage.setDOMStorageItemParameters; - "Database.disable": Database.disableParameters; - "Database.enable": Database.enableParameters; - "Database.executeSQL": Database.executeSQLParameters; - "Database.getDatabaseTableNames": Database.getDatabaseTableNamesParameters; "DeviceOrientation.clearDeviceOrientationOverride": DeviceOrientation.clearDeviceOrientationOverrideParameters; "DeviceOrientation.setDeviceOrientationOverride": DeviceOrientation.setDeviceOrientationOverrideParameters; "Emulation.canEmulate": Emulation.canEmulateParameters; @@ -21088,6 +21113,7 @@ Error was thrown. "Storage.setAttributionReportingTracking": Storage.setAttributionReportingTrackingParameters; "Storage.sendPendingAttributionReports": Storage.sendPendingAttributionReportsParameters; "Storage.getRelatedWebsiteSets": Storage.getRelatedWebsiteSetsParameters; + "Storage.getAffectedUrlsForThirdPartyCookieMetadata": Storage.getAffectedUrlsForThirdPartyCookieMetadataParameters; "SystemInfo.getInfo": SystemInfo.getInfoParameters; "SystemInfo.getFeatureState": SystemInfo.getFeatureStateParameters; "SystemInfo.getProcessInfo": SystemInfo.getProcessInfoParameters; @@ -21273,6 +21299,7 @@ Error was thrown. "Audits.checkContrast": Audits.checkContrastReturnValue; "Audits.checkFormsIssues": Audits.checkFormsIssuesReturnValue; "Extensions.loadUnpacked": Extensions.loadUnpackedReturnValue; + "Extensions.uninstall": Extensions.uninstallReturnValue; "Extensions.getStorageItems": Extensions.getStorageItemsReturnValue; "Extensions.removeStorageItems": Extensions.removeStorageItemsReturnValue; "Extensions.clearStorageItems": Extensions.clearStorageItemsReturnValue; @@ -21425,10 +21452,6 @@ Error was thrown. "DOMStorage.getDOMStorageItems": DOMStorage.getDOMStorageItemsReturnValue; "DOMStorage.removeDOMStorageItem": DOMStorage.removeDOMStorageItemReturnValue; "DOMStorage.setDOMStorageItem": DOMStorage.setDOMStorageItemReturnValue; - "Database.disable": Database.disableReturnValue; - "Database.enable": Database.enableReturnValue; - "Database.executeSQL": Database.executeSQLReturnValue; - "Database.getDatabaseTableNames": Database.getDatabaseTableNamesReturnValue; "DeviceOrientation.clearDeviceOrientationOverride": DeviceOrientation.clearDeviceOrientationOverrideReturnValue; "DeviceOrientation.setDeviceOrientationOverride": DeviceOrientation.setDeviceOrientationOverrideReturnValue; "Emulation.canEmulate": Emulation.canEmulateReturnValue; @@ -21705,6 +21728,7 @@ Error was thrown. "Storage.setAttributionReportingTracking": Storage.setAttributionReportingTrackingReturnValue; "Storage.sendPendingAttributionReports": Storage.sendPendingAttributionReportsReturnValue; "Storage.getRelatedWebsiteSets": Storage.getRelatedWebsiteSetsReturnValue; + "Storage.getAffectedUrlsForThirdPartyCookieMetadata": Storage.getAffectedUrlsForThirdPartyCookieMetadataReturnValue; "SystemInfo.getInfo": SystemInfo.getInfoReturnValue; "SystemInfo.getFeatureState": SystemInfo.getFeatureStateReturnValue; "SystemInfo.getProcessInfo": SystemInfo.getProcessInfoReturnValue; diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index d35137fbe2e07..033eed330460d 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -15,7 +15,6 @@ * limitations under the License. */ import { ChildProcess } from 'child_process'; -import { EventEmitter } from 'events'; import { Readable } from 'stream'; import { ReadStream } from 'fs'; import { Protocol } from './protocol'; @@ -2565,6 +2564,12 @@ export interface Page { */ colorScheme?: null|"light"|"dark"|"no-preference"; + /** + * Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. Passing `null` + * disables contrast emulation. + */ + contrast?: null|"no-preference"|"more"; + /** * Emulates `'forced-colors'` media feature, supported values are `'active'` and `'none'`. Passing `null` disables * forced colors emulation. @@ -9260,10 +9265,21 @@ export interface BrowserContext { setOffline(offline: boolean): Promise; /** - * Returns storage state for this browser context, contains current cookies and local storage snapshot. + * Returns storage state for this browser context, contains current cookies, local storage snapshot and IndexedDB + * snapshot. * @param options */ storageState(options?: { + /** + * Set to `true` to include [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) in the storage + * state snapshot. If your application uses IndexedDB to store authentication tokens, like Firebase Authentication, + * enable this. + * + * **NOTE** IndexedDBs with typed arrays are currently not supported. + * + */ + indexedDB?: boolean; + /** * The file path to save the storage state to. If * [`path`](https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state-option-path) is a @@ -9770,6 +9786,13 @@ export interface Browser { */ colorScheme?: null|"light"|"dark"|"no-preference"; + /** + * Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. See + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. + * Passing `null` resets emulation to system defaults. Defaults to `'no-preference'`. + */ + contrast?: null|"no-preference"|"more"; + /** * Specify device scale factor (can be thought of as dpr). Defaults to `1`. Learn more about * [emulating devices with device scale factor](https://playwright.dev/docs/emulation#devices). @@ -10049,12 +10072,12 @@ export interface Browser { sameSite: "Strict"|"Lax"|"None"; }>; - /** - * localStorage to set for context - */ origins: Array<{ origin: string; + /** + * localStorage to set for context + */ localStorage: Array<{ name: string; @@ -11627,7 +11650,8 @@ export interface ElementHandle extends JSHandle { * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink * box `#FF00FF` (customized by * [`maskColor`](https://playwright.dev/docs/api/class-elementhandle#element-handle-screenshot-option-mask-color)) - * that completely covers its bounding box. + * that completely covers its bounding box. The mask is also applied to invisible elements, see + * [Matching only visible elements](https://playwright.dev/docs/locators#matching-only-visible-elements) to disable that. */ mask?: Array; @@ -12176,12 +12200,6 @@ export interface Locator { * rejects, this method throws. * * **Usage** - * - * ```js - * const tweets = page.locator('.tweet .retweets'); - * expect(await tweets.evaluate(node => node.innerText)).toBe('10 retweets'); - * ``` - * * @param pageFunction Function to be evaluated in the page context. * @param arg Optional argument to pass to * [`pageFunction`](https://playwright.dev/docs/api/class-locator#locator-evaluate-option-expression). @@ -12207,12 +12225,6 @@ export interface Locator { * rejects, this method throws. * * **Usage** - * - * ```js - * const tweets = page.locator('.tweet .retweets'); - * expect(await tweets.evaluate(node => node.innerText)).toBe('10 retweets'); - * ``` - * * @param pageFunction Function to be evaluated in the page context. * @param arg Optional argument to pass to * [`pageFunction`](https://playwright.dev/docs/api/class-locator#locator-evaluate-option-expression). @@ -12429,7 +12441,7 @@ export interface Locator { /** * Captures the aria snapshot of the given element. Read more about [aria snapshots](https://playwright.dev/docs/aria-snapshots) and - * [expect(locator).toMatchAriaSnapshot(expected[, options])](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-match-aria-snapshot-1) + * [expect(locator).toMatchAriaSnapshot(expected[, options])](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-match-aria-snapshot) * for the corresponding assertion. * * **Usage** @@ -13111,6 +13123,11 @@ export interface Locator { * `
Playwright
`. */ hasText?: string|RegExp; + + /** + * Only matches visible or invisible elements. + */ + visible?: boolean; }): Locator; /** @@ -14062,9 +14079,9 @@ export interface Locator { * * ```html * * ``` * @@ -14313,7 +14330,8 @@ export interface Locator { }): Promise; /** - * Perform a tap gesture on the element matching the locator. + * Perform a tap gesture on the element matching the locator. For examples of emulating other gestures by manually + * dispatching touch events, see the [emulating legacy touch events](https://playwright.dev/docs/touch-events) page. * * **Details** * @@ -14566,6 +14584,11 @@ export interface BrowserType { * * **NOTE** Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers. * + * **NOTE** This connection is significantly lower fidelity than the Playwright protocol connection via + * [browserType.connect(wsEndpoint[, options])](https://playwright.dev/docs/api/class-browsertype#browser-type-connect). + * If you are experiencing issues or attempting to use advanced functionality, you probably want to use + * [browserType.connect(wsEndpoint[, options])](https://playwright.dev/docs/api/class-browsertype#browser-type-connect). + * * **Usage** * * ```js @@ -14591,6 +14614,11 @@ export interface BrowserType { * * **NOTE** Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers. * + * **NOTE** This connection is significantly lower fidelity than the Playwright protocol connection via + * [browserType.connect(wsEndpoint[, options])](https://playwright.dev/docs/api/class-browsertype#browser-type-connect). + * If you are experiencing issues or attempting to use advanced functionality, you probably want to use + * [browserType.connect(wsEndpoint[, options])](https://playwright.dev/docs/api/class-browsertype#browser-type-connect). + * * **Usage** * * ```js @@ -14605,10 +14633,12 @@ export interface BrowserType { */ connectOverCDP(options: ConnectOverCDPOptions & { wsEndpoint?: string }): Promise; /** - * This method attaches Playwright to an existing browser instance. When connecting to another browser launched via - * `BrowserType.launchServer` in Node.js, the major and minor version needs to match the client version (1.2.3 → is - * compatible with 1.2.x). - * @param wsEndpoint A browser websocket endpoint to connect to. + * This method attaches Playwright to an existing browser instance created via `BrowserType.launchServer` in Node.js. + * + * **NOTE** The major and minor version of the Playwright instance that connects needs to match the version of + * Playwright that launches the browser (1.2.3 → is compatible with 1.2.x). + * + * @param wsEndpoint A Playwright browser websocket endpoint to connect to. You obtain this endpoint via `BrowserServer.wsEndpoint`. * @param options */ connect(wsEndpoint: string, options?: ConnectOptions): Promise; @@ -14619,10 +14649,12 @@ export interface BrowserType { * @deprecated */ /** - * This method attaches Playwright to an existing browser instance. When connecting to another browser launched via - * `BrowserType.launchServer` in Node.js, the major and minor version needs to match the client version (1.2.3 → is - * compatible with 1.2.x). - * @param wsEndpoint A browser websocket endpoint to connect to. + * This method attaches Playwright to an existing browser instance created via `BrowserType.launchServer` in Node.js. + * + * **NOTE** The major and minor version of the Playwright instance that connects needs to match the version of + * Playwright that launches the browser (1.2.3 → is compatible with 1.2.x). + * + * @param wsEndpoint A Playwright browser websocket endpoint to connect to. You obtain this endpoint via `BrowserServer.wsEndpoint`. * @param options */ connect(options: ConnectOptions & { wsEndpoint?: string }): Promise; @@ -14795,6 +14827,13 @@ export interface BrowserType { */ colorScheme?: null|"light"|"dark"|"no-preference"; + /** + * Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. See + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. + * Passing `null` resets emulation to system defaults. Defaults to `'no-preference'`. + */ + contrast?: null|"no-preference"|"more"; + /** * Specify device scale factor (can be thought of as dpr). Defaults to `1`. Learn more about * [emulating devices with device scale factor](https://playwright.dev/docs/emulation#devices). @@ -16607,6 +16646,13 @@ export interface AndroidDevice { */ colorScheme?: null|"light"|"dark"|"no-preference"; + /** + * Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. See + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. + * Passing `null` resets emulation to system defaults. Defaults to `'no-preference'`. + */ + contrast?: null|"no-preference"|"more"; + /** * Specify device scale factor (can be thought of as dpr). Defaults to `1`. Learn more about * [emulating devices with device scale factor](https://playwright.dev/docs/emulation#devices). @@ -17482,6 +17528,12 @@ export interface APIRequest { */ extraHTTPHeaders?: { [key: string]: string; }; + /** + * Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status + * codes. + */ + failOnStatusCode?: boolean; + /** * Credentials for [HTTP authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication). If no * origin is specified, the username and password are sent to any servers upon unauthorized responses. @@ -18351,6 +18403,11 @@ export interface APIRequestContext { * @param options */ storageState(options?: { + /** + * Set to `true` to include IndexedDB in the storage state snapshot. + */ + indexedDB?: boolean; + /** * The file path to save the storage state to. If * [`path`](https://playwright.dev/docs/api/class-apirequestcontext#api-request-context-storage-state-option-path) is @@ -21049,6 +21106,9 @@ export interface Selectors { /** * The Touchscreen class operates in main-frame CSS pixels relative to the top-left corner of the viewport. Methods on * the touchscreen can only be used in browser contexts that have been initialized with `hasTouch` set to true. + * + * This class is limited to emulating tap gestures. For examples of other gestures simulated by manually dispatching + * touch events, see the [emulating legacy touch events](https://playwright.dev/docs/touch-events) page. */ export interface Touchscreen { /** @@ -21299,8 +21359,11 @@ export interface WebError { } /** - * The [WebSocket](https://playwright.dev/docs/api/class-websocket) class represents websocket connections in the - * page. + * The [WebSocket](https://playwright.dev/docs/api/class-websocket) class represents WebSocket connections within a + * page. It provides the ability to inspect and manipulate the data being transmitted and received. + * + * If you want to intercept or modify WebSocket frames, consider using + * [WebSocketRoute](https://playwright.dev/docs/api/class-websocketroute). */ export interface WebSocket { /** @@ -21785,7 +21848,8 @@ export interface LocatorScreenshotOptions { * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink * box `#FF00FF` (customized by * [`maskColor`](https://playwright.dev/docs/api/class-locator#locator-screenshot-option-mask-color)) that completely - * covers its bounding box. + * covers its bounding box. The mask is also applied to invisible elements, see + * [Matching only visible elements](https://playwright.dev/docs/locators#matching-only-visible-elements) to disable that. */ mask?: Array; @@ -21964,6 +22028,13 @@ export interface BrowserContextOptions { */ colorScheme?: null|"light"|"dark"|"no-preference"; + /** + * Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. See + * [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#page-emulate-media) for more details. + * Passing `null` resets emulation to system defaults. Defaults to `'no-preference'`. + */ + contrast?: null|"no-preference"|"more"; + /** * Specify device scale factor (can be thought of as dpr). Defaults to `1`. Learn more about * [emulating devices with device scale factor](https://playwright.dev/docs/emulation#devices). @@ -22210,12 +22281,12 @@ export interface BrowserContextOptions { sameSite: "Strict"|"Lax"|"None"; }>; - /** - * localStorage to set for context - */ origins: Array<{ origin: string; + /** + * localStorage to set for context + */ localStorage: Array<{ name: string; @@ -22443,7 +22514,8 @@ export interface PageScreenshotOptions { * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink * box `#FF00FF` (customized by * [`maskColor`](https://playwright.dev/docs/api/class-page#page-screenshot-option-mask-color)) that completely covers - * its bounding box. + * its bounding box. The mask is also applied to invisible elements, see + * [Matching only visible elements](https://playwright.dev/docs/locators#matching-only-visible-elements) to disable that. */ mask?: Array; diff --git a/packages/playwright-ct-core/.eslintrc.js b/packages/playwright-ct-core/.eslintrc.js deleted file mode 100644 index 84888f1ae3baf..0000000000000 --- a/packages/playwright-ct-core/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: "../../.eslintrc-with-ts-config.js", -}; diff --git a/packages/playwright-ct-core/package.json b/packages/playwright-ct-core/package.json index 60144fa7c3fd2..248484f75fa9f 100644 --- a/packages/playwright-ct-core/package.json +++ b/packages/playwright-ct-core/package.json @@ -1,6 +1,6 @@ { "name": "@playwright/experimental-ct-core", - "version": "1.50.0-next", + "version": "1.51.1", "description": "Playwright Component Testing Helpers", "repository": { "type": "git", @@ -26,8 +26,8 @@ } }, "dependencies": { - "playwright-core": "1.50.0-next", - "vite": "^5.2.8", - "playwright": "1.50.0-next" + "playwright-core": "1.51.1", + "vite": "^5.4.14 || ^6.0.0", + "playwright": "1.51.1" } } diff --git a/packages/playwright-ct-core/src/devServer.ts b/packages/playwright-ct-core/src/devServer.ts index 2152a672b3fd5..6e3b555a07918 100644 --- a/packages/playwright-ct-core/src/devServer.ts +++ b/packages/playwright-ct-core/src/devServer.ts @@ -16,12 +16,15 @@ import fs from 'fs'; import path from 'path'; + import { Watcher } from 'playwright/lib/fsWatcher'; -import type { PluginContext } from 'rollup'; + import { source as injectedSource } from './generated/indexSource'; -import { createConfig, populateComponentsFromTests, resolveDirs, transformIndexFile, frameworkConfig } from './viteUtils'; +import { createConfig, frameworkConfig, populateComponentsFromTests, resolveDirs, transformIndexFile } from './viteUtils'; + import type { ComponentRegistry } from './viteUtils'; import type { FullConfig } from 'playwright/test'; +import type { PluginContext } from 'rollup'; export async function runDevServer(config: FullConfig): Promise<() => Promise> { const { registerSourceFile, frameworkPluginFactory } = frameworkConfig(config); diff --git a/packages/playwright-ct-core/src/mount.ts b/packages/playwright-ct-core/src/mount.ts index a3bcfe064199e..68a2468c35d9d 100644 --- a/packages/playwright-ct-core/src/mount.ts +++ b/packages/playwright-ct-core/src/mount.ts @@ -14,13 +14,14 @@ * limitations under the License. */ -import type { Fixtures, Locator, Page, BrowserContextOptions, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, BrowserContext } from 'playwright/test'; -import type { Component, JsxComponent, MountOptions, ObjectComponentOptions } from '../types/component'; -import type { ContextReuseMode, FullConfigInternal } from '../../playwright/src/common/config'; -import type { ImportRef } from './injected/importRegistry'; import { wrapObject } from './injected/serializers'; import { Router } from './router'; + +import type { ContextReuseMode, FullConfigInternal } from '../../playwright/src/common/config'; import type { RouterFixture } from '../index'; +import type { ImportRef } from './injected/importRegistry'; +import type { Component, JsxComponent, MountOptions, ObjectComponentOptions } from '../types/component'; +import type { BrowserContext, BrowserContextOptions, Fixtures, Locator, Page, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions } from 'playwright/test'; let boundCallbacksForMount: Function[] = []; diff --git a/packages/playwright-ct-core/src/tsxTransform.ts b/packages/playwright-ct-core/src/tsxTransform.ts index 0af7c181b9517..f2fad4efa80bd 100644 --- a/packages/playwright-ct-core/src/tsxTransform.ts +++ b/packages/playwright-ct-core/src/tsxTransform.ts @@ -15,9 +15,11 @@ */ import path from 'path'; -import type { T, BabelAPI, PluginObj } from 'playwright/src/transform/babelBundle'; -import { types, declare, traverse } from 'playwright/lib/transform/babelBundle'; + +import { declare, traverse, types } from 'playwright/lib/transform/babelBundle'; import { setTransformData } from 'playwright/lib/transform/transform'; + +import type { BabelAPI, PluginObj, T } from 'playwright/src/transform/babelBundle'; const t: typeof T = types; let jsxComponentNames: Set; diff --git a/packages/playwright-ct-core/src/vitePlugin.ts b/packages/playwright-ct-core/src/vitePlugin.ts index ec738c87009f0..d31af197d1d18 100644 --- a/packages/playwright-ct-core/src/vitePlugin.ts +++ b/packages/playwright-ct-core/src/vitePlugin.ts @@ -15,24 +15,29 @@ */ import fs from 'fs'; -import type http from 'http'; -import type { AddressInfo } from 'net'; import path from 'path'; -import { assert, calculateSha1, getPlaywrightVersion, isURLAvailable } from 'playwright-core/lib/utils'; -import { debug } from 'playwright-core/lib/utilsBundle'; + import { setExternalDependencies } from 'playwright/lib/transform/compilationCache'; +import { resolveHook } from 'playwright/lib/transform/transform'; +import { removeDirAndLogToConsole } from 'playwright/lib/util'; import { stoppable } from 'playwright/lib/utilsBundle'; -import type { FullConfig, Suite } from 'playwright/types/testReporter'; -import type { PluginContext } from 'rollup'; -import type { Plugin, ResolveFn, ResolvedConfig } from 'vite'; -import type { TestRunnerPlugin } from '../../playwright/src/plugins'; +import { isURLAvailable } from 'playwright-core/lib/utils'; +import { assert, calculateSha1, getPlaywrightVersion } from 'playwright-core/lib/utils'; +import { debug } from 'playwright-core/lib/utilsBundle'; + +import { runDevServer } from './devServer'; import { source as injectedSource } from './generated/indexSource'; +import { createConfig, frameworkConfig, hasJSComponents, populateComponentsFromTests, resolveDirs, resolveEndpoint, transformIndexFile } from './viteUtils'; + import type { ImportInfo } from './tsxTransform'; import type { ComponentRegistry } from './viteUtils'; -import { createConfig, frameworkConfig, hasJSComponents, populateComponentsFromTests, resolveDirs, resolveEndpoint, transformIndexFile } from './viteUtils'; -import { resolveHook } from 'playwright/lib/transform/transform'; -import { runDevServer } from './devServer'; -import { removeDirAndLogToConsole } from 'playwright/lib/util'; +import type { TestRunnerPlugin } from '../../playwright/src/plugins'; +import type http from 'http'; +import type { AddressInfo } from 'net'; +import type { FullConfig, Suite } from 'playwright/types/testReporter'; +import type { PluginContext } from 'rollup'; +import type { Plugin, ResolveFn, ResolvedConfig } from 'vite'; + const log = debug('pw:vite'); diff --git a/packages/playwright-ct-core/src/viteUtils.ts b/packages/playwright-ct-core/src/viteUtils.ts index a9f7020999e90..58bfececc9e21 100644 --- a/packages/playwright-ct-core/src/viteUtils.ts +++ b/packages/playwright-ct-core/src/viteUtils.ts @@ -16,13 +16,16 @@ import fs from 'fs'; import path from 'path'; -import { debug } from 'playwright-core/lib/utilsBundle'; + import { getUserData } from 'playwright/lib/transform/compilationCache'; +import { resolveHook } from 'playwright/lib/transform/transform'; +import { debug } from 'playwright-core/lib/utilsBundle'; + +import type { ImportInfo } from './tsxTransform'; import type { PlaywrightTestConfig as BasePlaywrightTestConfig } from 'playwright/types/test'; import type { FullConfig } from 'playwright/types/testReporter'; import type { InlineConfig, Plugin, TransformResult, UserConfig } from 'vite'; -import type { ImportInfo } from './tsxTransform'; -import { resolveHook } from 'playwright/lib/transform/transform'; + const log = debug('pw:vite'); diff --git a/packages/playwright-ct-react/package.json b/packages/playwright-ct-react/package.json index 39a8e98a151ef..c5dd8f8a0bbf1 100644 --- a/packages/playwright-ct-react/package.json +++ b/packages/playwright-ct-react/package.json @@ -1,6 +1,6 @@ { "name": "@playwright/experimental-ct-react", - "version": "1.50.0-next", + "version": "1.51.1", "description": "Playwright Component Testing for React", "repository": { "type": "git", @@ -30,7 +30,7 @@ "./package.json": "./package.json" }, "dependencies": { - "@playwright/experimental-ct-core": "1.50.0-next", + "@playwright/experimental-ct-core": "1.51.1", "@vitejs/plugin-react": "^4.2.1" }, "bin": { diff --git a/packages/playwright-ct-react17/package.json b/packages/playwright-ct-react17/package.json index 41665bfb9ba0e..f63c22f63e8d9 100644 --- a/packages/playwright-ct-react17/package.json +++ b/packages/playwright-ct-react17/package.json @@ -1,6 +1,6 @@ { "name": "@playwright/experimental-ct-react17", - "version": "1.50.0-next", + "version": "1.51.1", "description": "Playwright Component Testing for React", "repository": { "type": "git", @@ -30,7 +30,7 @@ "./package.json": "./package.json" }, "dependencies": { - "@playwright/experimental-ct-core": "1.50.0-next", + "@playwright/experimental-ct-core": "1.51.1", "@vitejs/plugin-react": "^4.2.1" }, "bin": { diff --git a/packages/playwright-ct-svelte/package.json b/packages/playwright-ct-svelte/package.json index 7afba0363204c..29b563c6193c3 100644 --- a/packages/playwright-ct-svelte/package.json +++ b/packages/playwright-ct-svelte/package.json @@ -1,6 +1,6 @@ { "name": "@playwright/experimental-ct-svelte", - "version": "1.50.0-next", + "version": "1.51.1", "description": "Playwright Component Testing for Svelte", "repository": { "type": "git", @@ -30,7 +30,7 @@ "./package.json": "./package.json" }, "dependencies": { - "@playwright/experimental-ct-core": "1.50.0-next", + "@playwright/experimental-ct-core": "1.51.1", "@sveltejs/vite-plugin-svelte": "^3.0.1" }, "devDependencies": { diff --git a/packages/playwright-ct-vue/package.json b/packages/playwright-ct-vue/package.json index fe4846139478d..ea330652e4d55 100644 --- a/packages/playwright-ct-vue/package.json +++ b/packages/playwright-ct-vue/package.json @@ -1,6 +1,6 @@ { "name": "@playwright/experimental-ct-vue", - "version": "1.50.0-next", + "version": "1.51.1", "description": "Playwright Component Testing for Vue", "repository": { "type": "git", @@ -30,7 +30,7 @@ "./package.json": "./package.json" }, "dependencies": { - "@playwright/experimental-ct-core": "1.50.0-next", + "@playwright/experimental-ct-core": "1.51.1", "@vitejs/plugin-vue": "^5.2.0" }, "bin": { diff --git a/packages/playwright-firefox/package.json b/packages/playwright-firefox/package.json index 44832c5532c8a..930cf8761f2e3 100644 --- a/packages/playwright-firefox/package.json +++ b/packages/playwright-firefox/package.json @@ -1,6 +1,6 @@ { "name": "playwright-firefox", - "version": "1.50.0-next", + "version": "1.51.1", "description": "A high-level API to automate Firefox", "repository": { "type": "git", @@ -30,6 +30,6 @@ "install": "node install.js" }, "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" } } diff --git a/packages/playwright-test/package.json b/packages/playwright-test/package.json index dcf74e1111e65..0d229995bafa9 100644 --- a/packages/playwright-test/package.json +++ b/packages/playwright-test/package.json @@ -1,6 +1,6 @@ { "name": "@playwright/test", - "version": "1.50.0-next", + "version": "1.51.1", "description": "A high-level API to automate web browsers", "repository": { "type": "git", @@ -30,6 +30,6 @@ }, "scripts": {}, "dependencies": { - "playwright": "1.50.0-next" + "playwright": "1.51.1" } } diff --git a/packages/playwright-tools/.npmignore b/packages/playwright-tools/.npmignore new file mode 100644 index 0000000000000..9b62c46c55293 --- /dev/null +++ b/packages/playwright-tools/.npmignore @@ -0,0 +1,8 @@ +**/* +README.md +LICENSE +!lib/* +!browser.js +!browser.d.ts +!computer-20241022.js +!computer-20241022.d.ts diff --git a/packages/playwright-tools/README.md b/packages/playwright-tools/README.md new file mode 100644 index 0000000000000..ce4a9dd7c6724 --- /dev/null +++ b/packages/playwright-tools/README.md @@ -0,0 +1 @@ +> **BEWARE** This package is EXPERIMENTAL and does not respect semver. diff --git a/packages/playwright-tools/browser.d.ts b/packages/playwright-tools/browser.d.ts new file mode 100644 index 0000000000000..e06589e947538 --- /dev/null +++ b/packages/playwright-tools/browser.d.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type playwright from 'playwright'; +import { ToolDeclaration, JSONSchemaType } from './types'; + +export type ToolResult = { + error?: string; + code: Array; + snapshot: string; +} + +export type ToolCall = (page: playwright.Page, tool: string, parameters: { [key: string]: JSONSchemaType; }) => Promise; + +export const schema: ToolDeclaration[]; +export const call: ToolCall; +export const snapshot: (page) => Promise; diff --git a/packages/playwright-tools/browser.js b/packages/playwright-tools/browser.js new file mode 100644 index 0000000000000..d0475e384b5aa --- /dev/null +++ b/packages/playwright-tools/browser.js @@ -0,0 +1,19 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const { schema, call, snapshot } = require('./lib/tools/browser'); + +module.exports = { schema, call, snapshot }; diff --git a/packages/playwright-tools/computer-20241022.d.ts b/packages/playwright-tools/computer-20241022.d.ts new file mode 100644 index 0000000000000..ce0f821d6d380 --- /dev/null +++ b/packages/playwright-tools/computer-20241022.d.ts @@ -0,0 +1,28 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type playwright from 'playwright'; +import { JSONSchemaType } from './types'; + +export type ToolResult = { + output?: string; + error?: string; + base64_image?: string; +}; + +export type ToolCall = (page: playwright.Page, tool: string, parameters: { [key: string]: JSONSchemaType; }) => Promise; + +export const call: ToolCall; diff --git a/packages/playwright-tools/computer-20241022.js b/packages/playwright-tools/computer-20241022.js new file mode 100644 index 0000000000000..030d0e57e2918 --- /dev/null +++ b/packages/playwright-tools/computer-20241022.js @@ -0,0 +1,19 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const { call } = require('./lib/tools/computer-20241022'); + +module.exports = { call }; diff --git a/packages/playwright-tools/package.json b/packages/playwright-tools/package.json new file mode 100644 index 0000000000000..ca0dce67d8038 --- /dev/null +++ b/packages/playwright-tools/package.json @@ -0,0 +1,36 @@ +{ + "name": "@playwright/experimental-tools", + "private": true, + "version": "0.0.0", + "description": "Playwright Tools for AI", + "repository": { + "type": "git", + "url": "git+https://github.com/microsoft/playwright.git" + }, + "homepage": "https://playwright.dev", + "engines": { + "node": ">=18" + }, + "author": { + "name": "Microsoft Corporation" + }, + "license": "Apache-2.0", + "exports": { + "./browser": { + "types": "./browser.d.ts", + "default": "./browser.js" + }, + "./computer-20241022": { + "types": "./computer-20241022.d.ts", + "default": "./computer-20241022.js" + }, + "./package.json": "./package.json" + }, + "dependencies": { + "playwright": "1.51.1" + }, + "devDependencies": { + "@anthropic-ai/sdk": "^0.33.1", + "openai": "^4.79.1" + } +} diff --git a/packages/playwright-tools/src/examples/browser-anthropic.ts b/packages/playwright-tools/src/examples/browser-anthropic.ts new file mode 100644 index 0000000000000..d7dd750a188b1 --- /dev/null +++ b/packages/playwright-tools/src/examples/browser-anthropic.ts @@ -0,0 +1,143 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* eslint-disable no-console */ + +import Anthropic from '@anthropic-ai/sdk'; +import browser from '@playwright/experimental-tools/browser'; +import dotenv from 'dotenv'; +import playwright from 'playwright'; + +dotenv.config(); + +const anthropic = new Anthropic(); + +export const system = ` +You are a web tester. + + +- Perform test according to the provided checklist +- Use browser tools to perform actions on web page +- Never ask questions, always perform a best guess action +- Use one tool at a time, wait for its result before proceeding. +- When ready use "reportResult" tool to report result +`; + +const reportTool: Anthropic.Tool = { + name: 'reportResult', + description: 'Submit test result', + input_schema: { + type: 'object', + properties: { + 'success': { type: 'boolean', description: 'Whether test passed' }, + 'result': { type: 'string', description: 'Result of the test if some information has been requested' }, + 'error': { type: 'string', description: 'Error message if test failed' } + }, + required: ['success'] + } +}; + +type Message = Anthropic.Beta.Messages.BetaMessageParam & { + history: Anthropic.Beta.Messages.BetaMessageParam['content'] +}; + +async function anthropicAgentLoop(page: playwright.Page, task: string) { + // Convert them into tools for Anthropic. + const pageTools: Anthropic.Tool[] = browser.schema.map(tool => { + return { + name: tool.name, + description: tool.description, + input_schema: tool.parameters as any, + }; + }); + + // Add report tool. + const tools = [reportTool, ...pageTools]; + + const history: Message[] = [{ + role: 'user', + history: `Task: ${task}`, + content: `Task: ${task}\n\n${await browser.snapshot(page)}`, + }]; + + // Run agentic loop, cap steps. + for (let i = 0; i < 50; i++) { + const response = await anthropic.messages.create({ + model: 'claude-3-5-sonnet-20241022', + max_tokens: 1024, + temperature: 0, + tools, + system, + messages: toAnthropicMessages(history), + }); + history.push({ role: 'assistant', content: response.content, history: response.content }); + + const toolUse = response.content.find(block => block.type === 'tool_use'); + if (!toolUse) { + history.push({ role: 'user', content: 'expected exactly one tool call', history: 'expected exactly one tool call' }); + continue; + } + + if (toolUse.name === 'reportResult') { + console.log(toolUse.input); + return; + } + + // Run the Playwright tool. + const { error, snapshot, code } = await browser.call(page, toolUse.name, toolUse.input as any); + if (code.length) + console.log(code.join('\n')); + + // Report the result. + const resultText = error ? `Error: ${error}\n` : 'Done\n'; + history.push({ + role: 'user', + content: [{ + type: 'tool_result', + tool_use_id: toolUse.id, + content: [{ type: 'text', text: resultText + snapshot }], + }], + history: [{ + type: 'tool_result', + tool_use_id: toolUse.id, + content: [{ type: 'text', text: resultText }], + }], + }); + } +} + +function toAnthropicMessages(messages: Message[]): Anthropic.Beta.Messages.BetaMessageParam[] { + return messages.map((message, i) => { + if (i === messages.length - 1) + return { ...message, history: undefined }; + return { ...message, content: message.history, history: undefined }; + }); +} + +async function main() { + const browser = await playwright.chromium.launch({ headless: false }); + const page = await browser.newPage(); + await anthropicAgentLoop(page, ` + - Go to http://github.com/microsoft + - Search for "playwright" repository + - Navigate to it + - Switch into the Issues tab + - Report 3 first issues + `); + await browser.close(); +} + +void main(); diff --git a/packages/playwright-tools/src/examples/browser-openai.ts b/packages/playwright-tools/src/examples/browser-openai.ts new file mode 100644 index 0000000000000..c3f1752d78544 --- /dev/null +++ b/packages/playwright-tools/src/examples/browser-openai.ts @@ -0,0 +1,157 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* eslint-disable no-console */ + +import browser from '@playwright/experimental-tools/browser'; +import dotenv from 'dotenv'; +import OpenAI from 'openai'; +import playwright from 'playwright'; + +import type { ChatCompletionMessageParam, ChatCompletionTool } from 'openai/resources'; + +dotenv.config(); + +const openai = new OpenAI(); + +export const system = ` +You are a web tester. + +to +- Perform test according to the provided checklist +- Use browser tools to perform actions on web page +- Never ask questions, always perform a best guess action +- When ready use "reportResult" tool to report result +- You can only make one tool call at a time. +`; + +type Message = ChatCompletionMessageParam & { + history: any +}; + +const reportTool: ChatCompletionTool = { + type: 'function', + function: { + name: 'reportResult', + description: 'Submit test result', + parameters: { + type: 'object', + properties: { + success: { type: 'boolean', description: 'Whether test passed' }, + result: { type: 'string', description: 'Result of the test if requested' }, + error: { type: 'string', description: 'Error if test failed' }, + }, + required: ['success'], + additionalProperties: false, + }, + } +}; + +async function openAIAgentLoop(page: playwright.Page, task: string) { + const pageTools: ChatCompletionTool[] = browser.schema.map(tool => ({ + type: 'function', + function: { + name: tool.name, + description: tool.description, + parameters: { + ...tool.parameters, + additionalProperties: false, + }, + } + })); + + const tools = [reportTool, ...pageTools]; + + const history: Message[] = [ + { + role: 'system', content: system, history: system + }, + { + role: 'user', + history: `Task: ${task}`, + content: `Task: ${task}\n\n${await browser.snapshot(page)}`, + } + ]; + + // Run agentic loop, cap steps. + for (let i = 0; i < 50; i++) { + const completion = await openai.chat.completions.create({ + model: 'gpt-4o', + messages: toOpenAIMessages(history), + tools, + tool_choice: 'required', + store: true, + }); + + const toolCalls = completion.choices[0]?.message?.tool_calls; + if (!toolCalls || toolCalls.length !== 1 || toolCalls[0].type !== 'function') { + history.push({ role: 'user', content: 'expected exactly one tool call', history: 'expected exactly one tool call' }); + continue; + } + + const toolCall = toolCalls[0]; + if (toolCall.function.name === 'reportResult') { + console.log(JSON.parse(toolCall.function.arguments)); + return; + } + + history.push({ ...completion.choices[0].message, history: null }); + + // Run the Playwright tool. + const params = JSON.parse(toolCall.function.arguments); + const { error, snapshot, code } = await browser.call(page, toolCall.function.name, params); + if (code.length) + console.log(code.join('\n')); + + if (toolCall.function.name === 'log') + return; + + // Report the result. + const resultText = error ? `Error: ${error}\n` : 'Done\n'; + history.push({ + role: 'tool', + tool_call_id: toolCall.id, + content: resultText + snapshot, + history: resultText, + }); + } +} + +function toOpenAIMessages(messages: Message[]): ChatCompletionMessageParam[] { + return messages.map((message, i) => { + const copy: Message = { ...message }; + delete copy.history; + if (i === messages.length - 1) + return copy; + copy.content = message.history; + return copy; + }); +} + +async function main() { + const browser = await playwright.chromium.launch({ headless: false }); + const page = await browser.newPage(); + await openAIAgentLoop(page, ` + - Go to http://github.com/microsoft + - Search for "playwright" repository + - Navigate to it + - Switch into the Issues tab + - Report 3 first issues + `); + await browser.close(); +} + +void main(); diff --git a/packages/playwright-tools/src/examples/computer-20241022-anthropic.ts b/packages/playwright-tools/src/examples/computer-20241022-anthropic.ts new file mode 100644 index 0000000000000..2d8ee4b7f98f1 --- /dev/null +++ b/packages/playwright-tools/src/examples/computer-20241022-anthropic.ts @@ -0,0 +1,150 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* eslint-disable no-console */ + +import Anthropic from '@anthropic-ai/sdk'; +import computer from '@playwright/experimental-tools/computer-20241022'; +import dotenv from 'dotenv'; +import playwright from 'playwright'; + +import type { BetaImageBlockParam, BetaTextBlockParam } from '@anthropic-ai/sdk/resources/beta/messages/messages'; +import type { ToolResult } from '@playwright/experimental-tools/computer-20241022'; + +dotenv.config(); + +const anthropic = new Anthropic(); + +export const system = ` +You are a web tester. + + +- Perform test according to the provided checklist +- Use browser tools to perform actions on web page +- Never ask questions, always perform a best guess action +- Use one tool at a time, wait for its result before proceeding. +- When ready use "reportResult" tool to report result +`; + +const computerTool: Anthropic.Beta.BetaToolUnion = { + type: 'computer_20241022', + name: 'computer', + display_width_px: 1920, + display_height_px: 1080, + display_number: 1, +}; + +const reportTool: Anthropic.Tool = { + name: 'reportResult', + description: 'Submit test result', + input_schema: { + type: 'object', + properties: { + 'success': { type: 'boolean', description: 'Whether test passed' }, + 'result': { type: 'string', description: 'Result of the test if some information has been requested' }, + 'error': { type: 'string', description: 'Error message if test failed' } + }, + required: ['success'] + } +}; + +type Message = Anthropic.Beta.Messages.BetaMessageParam & { + history: Anthropic.Beta.Messages.BetaMessageParam['content'] +}; + +async function anthropicAgentLoop(page: playwright.Page, task: string) { + // Add report tool. + const tools = [reportTool, computerTool]; + + const history: Message[] = [{ + role: 'user', + history: `Task: ${task}`, + content: `Task: ${task}`, + }]; + + // Run agentic loop, cap steps. + for (let i = 0; i < 50; i++) { + const response = await anthropic.beta.messages.create({ + model: 'claude-3-5-sonnet-20241022', + max_tokens: 1024, + temperature: 0, + tools, + system, + messages: toAnthropicMessages(history), + betas: ['computer-use-2024-10-22'], + }); + + history.push({ role: 'assistant', content: response.content, history: response.content }); + + const toolUse = response.content.find(block => block.type === 'tool_use'); + if (!toolUse) { + history.push({ role: 'user', content: 'expected exactly one tool call', history: 'expected exactly one tool call' }); + continue; + } + + if (toolUse.name === 'reportResult') { + console.log(toolUse.input); + return; + } + + const result: ToolResult = await computer.call(page, toolUse.name, toolUse.input as any); + const contentEntry: BetaTextBlockParam | BetaImageBlockParam = result.base64_image ? { + type: 'image', + source: { type: 'base64', media_type: 'image/jpeg', data: result.base64_image } + } : { + type: 'text', + text: result.output || '', + }; + history.push({ + role: 'user', + content: [{ + type: 'tool_result', + tool_use_id: toolUse.id, + content: [contentEntry], + }], + history: [{ + type: 'tool_result', + tool_use_id: toolUse.id, + content: [{ type: 'text', text: '' }], + }], + }); + } +} + +function toAnthropicMessages(messages: Message[]): Anthropic.Beta.Messages.BetaMessageParam[] { + return messages.map((message, i) => { + if (i === messages.length - 1) + return { ...message, history: undefined }; + return { ...message, content: message.history, history: undefined }; + }); +} + +const githubTask = ` + - Search for "playwright" repository + - Navigate to it + - Switch into the Issues tab + - Report 3 first issues +`; + +async function main() { + const browser = await playwright.chromium.launch({ headless: false }); + const page = await browser.newPage(); + await page.goto('http://github.com/microsoft'); + await anthropicAgentLoop(page, githubTask); + await browser.close(); +} + +void main(); diff --git a/packages/playwright-tools/src/tools/browser.ts b/packages/playwright-tools/src/tools/browser.ts new file mode 100644 index 0000000000000..1ca7fb074a755 --- /dev/null +++ b/packages/playwright-tools/src/tools/browser.ts @@ -0,0 +1,150 @@ +/** + * Copyright 2017 Google Inc. All rights reserved. + * Modifications copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { waitForNetwork } from './utils'; + +import type { ToolResult } from '../../browser'; +import type { JSONSchemaType, ToolDeclaration } from '../../types'; +import type playwright from 'playwright'; + + +type LocatorEx = playwright.Locator & { + _generateLocatorString: () => Promise; +}; + +const intentProperty = { + intent: { + type: 'string', + description: 'Intent behind this particular action. Used as a comment.', + } +}; + +const elementIdProperty = { + elementId: { + type: 'number', + description: 'Target element', + } +}; + +export const schema: ToolDeclaration[] = [ + { + name: 'navigate', + description: 'Navigate to a URL', + parameters: { + type: 'object', + properties: { + ...intentProperty, + url: { + type: 'string', + description: 'URL to navigate to', + }, + }, + required: ['intent', 'elementId'], + } + }, + { + name: 'click', + description: 'Perform click on a web page', + parameters: { + type: 'object', + properties: { + ...intentProperty, + ...elementIdProperty, + }, + required: ['intent', 'elementId'], + } + }, + { + name: 'enterText', + description: 'Enter text into editable element', + parameters: { + type: 'object', + properties: { + ...intentProperty, + ...elementIdProperty, + text: { + type: 'string', + description: 'Text to enter', + }, + submit: { + type: 'boolean', + description: 'Whether to submit entered text (press Enter after)' + } + }, + required: ['intent', 'elementId', 'text'], + } + }, + { + name: 'wait', + description: `Wait for given amount of time to see if the page updates. Use it after action if you think page is not ready yet`, + parameters: { + type: 'object', + properties: { + ...intentProperty, + time: { + type: 'integer', + description: 'Time to wait in seconds', + }, + }, + required: ['intent', 'time'], + } + }, +]; + +export async function call(page: playwright.Page, toolName: string, params: Record): Promise { + const code: string[] = []; + try { + await waitForNetwork(page, async () => { + await performAction(page, toolName, params, code); + }); + } catch (e) { + return { error: e.message, snapshot: await snapshot(page), code }; + } + return { snapshot: await snapshot(page), code }; +} + +export async function snapshot(page: playwright.Page) { + const params = { _id: true } as any; + return `\n${await page.locator('body').ariaSnapshot(params)}\n`; +} + +async function performAction(page: playwright.Page, toolName: string, params: Record, code: string[]) { + const locator = elementLocator(page, params); + code.push((params.intent as string).split('\n').map(line => `// ${line}`).join('\n')); + if (toolName === 'navigate') { + code.push(`await page.goto(${JSON.stringify(params.url)})`); + await page.goto(params.url as string); + } else if (toolName === 'wait') { + await page.waitForTimeout(Math.min(10000, params.time as number * 1000)); + } else if (toolName === 'click') { + code.push(`await page.${await locator._generateLocatorString()}.click()`); + await locator.click(); + } else if (toolName === 'enterText') { + code.push(`await page.${await locator._generateLocatorString()}.click()`); + await locator.click(); + code.push(`await page.${await locator._generateLocatorString()}.fill(${JSON.stringify(params.text)})`); + await locator.fill(params.text as string); + if (params.submit) { + code.push(`await page.${await locator._generateLocatorString()}.press("Enter")`); + await locator.press('Enter'); + } + } +} + +function elementLocator(page: playwright.Page, params: any): LocatorEx { + return page.locator(`internal:aria-id=${params.elementId}`) as LocatorEx; +} diff --git a/packages/playwright-tools/src/tools/computer-20241022.ts b/packages/playwright-tools/src/tools/computer-20241022.ts new file mode 100644 index 0000000000000..2a7574c485aaf --- /dev/null +++ b/packages/playwright-tools/src/tools/computer-20241022.ts @@ -0,0 +1,160 @@ +/** + * Copyright 2017 Google Inc. All rights reserved. + * Modifications copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { waitForNetwork } from './utils'; + +import type { ToolResult } from '../../computer-20241022'; +import type { JSONSchemaType } from '../../types'; +import type playwright from 'playwright'; + + +export async function call(page: playwright.Page, toolName: string, input: Record): Promise { + if (toolName !== 'computer') + throw new Error('Unsupported tool'); + return await waitForNetwork(page, async () => { + return await performAction(page, toolName, input); + }); +} + +type PageState = { + x: number; + y: number; +}; + +const pageStateSymbol = Symbol('pageState'); + +function pageState(page: playwright.Page): PageState { + if (!(page as any)[pageStateSymbol]) + (page as any)[pageStateSymbol] = { x: 0, y: 0 }; + return (page as any)[pageStateSymbol]; +} + +async function performAction(page: playwright.Page, toolName: string, input: Record): Promise { + const state = pageState(page); + const { action } = input as { action: string }; + if (action === 'screenshot') { + const screenshot = await page.screenshot({ type: 'jpeg', quality: 50, scale: 'css' }); + return { + output: 'Screenshot', + base64_image: screenshot.toString('base64'), + }; + } + if (action === 'mouse_move') { + const { coordinate } = input as { coordinate: [number, number] }; + state.x = coordinate[0]; + state.y = coordinate[1]; + await page.mouse.move(state.x, state.y); + return { output: 'Mouse moved' }; + } + if (action === 'left_click') { + await page.mouse.down(); + await page.mouse.up(); + return { output: 'Left clicked' }; + } + if (action === 'left_click_drag') { + await page.mouse.down(); + const { coordinate } = input as { coordinate: [number, number] }; + state.x = coordinate[0]; + state.y = coordinate[1]; + await page.mouse.move(state.x, state.y); + await page.mouse.up(); + return { output: 'Left dragged' }; + } + if (action === 'right_click') { + await page.mouse.down({ button: 'right' }); + await page.mouse.up({ button: 'right' }); + return { output: 'Right clicked' }; + } + if (action === 'double_click') { + await page.mouse.down(); + await page.mouse.up(); + await page.mouse.down(); + await page.mouse.up(); + return { output: 'Double clicked' }; + } + if (action === 'middle_click') { + await page.mouse.down({ button: 'middle' }); + await page.mouse.up({ button: 'middle' }); + return { output: 'Middle clicked' }; + } + if (action === 'key') { + const { text } = input as { text: string }; + await page.keyboard.press(xToPlaywright(text)); + return { output: 'Text typed' }; + } + if (action === 'cursor_position') + return { output: `X=${state.x},Y=${state.y}` }; + throw new Error('Unimplemented tool: ' + toolName); +} + +const xToPlaywrightKeyMap = new Map([ + ['BackSpace', 'Backspace'], + ['Tab', 'Tab'], + ['Return', 'Enter'], + ['Escape', 'Escape'], + ['space', ' '], + ['Delete', 'Delete'], + ['Home', 'Home'], + ['End', 'End'], + ['Left', 'ArrowLeft'], + ['Up', 'ArrowUp'], + ['Right', 'ArrowRight'], + ['Down', 'ArrowDown'], + ['Insert', 'Insert'], + ['Page_Up', 'PageUp'], + ['Page_Down', 'PageDown'], + ['F1', 'F1'], + ['F2', 'F2'], + ['F3', 'F3'], + ['F4', 'F4'], + ['F5', 'F5'], + ['F6', 'F6'], + ['F7', 'F7'], + ['F8', 'F8'], + ['F9', 'F9'], + ['F10', 'F10'], + ['F11', 'F11'], + ['F12', 'F12'], + ['Shift_L', 'Shift'], + ['Shift_R', 'Shift'], + ['Control_L', 'Control'], + ['Control_R', 'Control'], + ['Alt_L', 'Alt'], + ['Alt_R', 'Alt'], + ['Super_L', 'Meta'], + ['Super_R', 'Meta'], +]); + +const xToPlaywrightModifierMap = new Map([ + ['alt', 'Alt'], + ['control', 'Control'], + ['meta', 'Meta'], + ['shift', 'Shift'], +]); + + +const xToPlaywright = (key: string) => { + const tokens = key.split('+'); + if (tokens.length === 1) + return xToPlaywrightKeyMap.get(key) || key; + if (tokens.length === 2) { + const modifier = xToPlaywrightModifierMap.get(tokens[0]); + const key = xToPlaywrightKeyMap.get(tokens[1]) || tokens[1]; + return modifier + '+' + key; + } + throw new Error('Invalid key: ' + key); +}; diff --git a/packages/playwright-tools/src/tools/utils.ts b/packages/playwright-tools/src/tools/utils.ts new file mode 100644 index 0000000000000..71c49e4fe19d0 --- /dev/null +++ b/packages/playwright-tools/src/tools/utils.ts @@ -0,0 +1,72 @@ +/** + * Copyright 2017 Google Inc. All rights reserved. + * Modifications copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ManualPromise } from 'playwright-core/lib/utils'; + +import type playwright from 'playwright'; + +export async function waitForNetwork(page: playwright.Page, callback: () => Promise): Promise { + const requests = new Set(); + let frameNavigated = false; + const waitBarrier = new ManualPromise(); + + const requestListener = (request: playwright.Request) => requests.add(request); + const requestFinishedListener = (request: playwright.Request) => { + requests.delete(request); + if (!requests.size) + waitBarrier.resolve(); + }; + + const frameNavigateListener = (frame: playwright.Frame) => { + if (frame.parentFrame()) + return; + frameNavigated = true; + dispose(); + clearTimeout(timeout); + void frame.waitForLoadState('load').then(() => { + waitBarrier.resolve(); + }); + }; + + const onTimeout = () => { + dispose(); + waitBarrier.resolve(); + }; + + page.on('request', requestListener); + page.on('requestfinished', requestFinishedListener); + page.on('framenavigated', frameNavigateListener); + const timeout = setTimeout(onTimeout, 10000); + + const dispose = () => { + page.off('request', requestListener); + page.off('requestfinished', requestFinishedListener); + page.off('framenavigated', frameNavigateListener); + clearTimeout(timeout); + }; + + try { + const result = await callback(); + if (!requests.size && !frameNavigated) + waitBarrier.resolve(); + await waitBarrier; + await page.evaluate(() => new Promise(f => setTimeout(f, 1000))); + return result; + } finally { + dispose(); + } +} diff --git a/packages/playwright-tools/types.d.ts b/packages/playwright-tools/types.d.ts new file mode 100644 index 0000000000000..5fe61526c2c50 --- /dev/null +++ b/packages/playwright-tools/types.d.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type playwright from 'playwright'; + +export type JSONSchemaType = string | number | boolean | JSONSchemaObject | JSONSchemaArray | null; +interface JSONSchemaObject { [key: string]: JSONSchemaType; } +interface JSONSchemaArray extends Array {} + +export type ToolDeclaration = { + name: string; + description: string; + parameters: any; +}; diff --git a/packages/playwright-webkit/package.json b/packages/playwright-webkit/package.json index 9fd72b1c84694..00b3bf177f98c 100644 --- a/packages/playwright-webkit/package.json +++ b/packages/playwright-webkit/package.json @@ -1,6 +1,6 @@ { "name": "playwright-webkit", - "version": "1.50.0-next", + "version": "1.51.1", "description": "A high-level API to automate WebKit", "repository": { "type": "git", @@ -30,6 +30,6 @@ "install": "node install.js" }, "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" } } diff --git a/packages/playwright/.eslintrc.js b/packages/playwright/.eslintrc.js deleted file mode 100644 index b7e707b35ffd1..0000000000000 --- a/packages/playwright/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - extends: '../../.eslintrc-with-ts-config.js', - rules: { - '@typescript-eslint/no-floating-promises': 'error', - }, -}; diff --git a/packages/playwright/bundles/babel/src/babelBundleImpl.ts b/packages/playwright/bundles/babel/src/babelBundleImpl.ts index 54822134ea13b..2810a1bd5cad3 100644 --- a/packages/playwright/bundles/babel/src/babelBundleImpl.ts +++ b/packages/playwright/bundles/babel/src/babelBundleImpl.ts @@ -15,15 +15,17 @@ */ import path from 'path'; + +import * as babel from '@babel/core'; +import traverseFunction from '@babel/traverse'; + import type { BabelFileResult, NodePath, PluginObj, TransformOptions } from '@babel/core'; -import type { TSExportAssignment, ImportDeclaration } from '@babel/types'; import type { TemplateBuilder } from '@babel/template'; -import * as babel from '@babel/core'; +import type { ImportDeclaration, TSExportAssignment } from '@babel/types'; export { codeFrameColumns } from '@babel/code-frame'; export { declare } from '@babel/helper-plugin-utils'; export { types } from '@babel/core'; -import traverseFunction from '@babel/traverse'; export const traverse = traverseFunction; function babelTransformOptions(isTypeScript: boolean, isModule: boolean, pluginsPrologue: [string, any?][], pluginsEpilogue: [string, any?][]): TransformOptions { @@ -118,15 +120,15 @@ function isTypeScript(filename: string) { return filename.endsWith('.ts') || filename.endsWith('.tsx') || filename.endsWith('.mts') || filename.endsWith('.cts'); } -export function babelTransform(code: string, filename: string, isModule: boolean, pluginsPrologue: [string, any?][], pluginsEpilogue: [string, any?][]): BabelFileResult { +export function babelTransform(code: string, filename: string, isModule: boolean, pluginsPrologue: [string, any?][], pluginsEpilogue: [string, any?][]): BabelFileResult | null { if (isTransforming) - return {}; + return null; // Prevent reentry while requiring plugins lazily. isTransforming = true; try { const options = babelTransformOptions(isTypeScript(filename), isModule, pluginsPrologue, pluginsEpilogue); - return babel.transform(code, { filename, ...options })!; + return babel.transform(code, { filename, ...options }); } finally { isTransforming = false; } diff --git a/packages/playwright/bundles/expect/src/expectBundleImpl.ts b/packages/playwright/bundles/expect/src/expectBundleImpl.ts index 875b48e614a43..0ffe8acbd80c2 100644 --- a/packages/playwright/bundles/expect/src/expectBundleImpl.ts +++ b/packages/playwright/bundles/expect/src/expectBundleImpl.ts @@ -14,11 +14,13 @@ * limitations under the License. */ +import * as mu from 'jest-matcher-utils'; + +import * as am from '../third_party/asymmetricMatchers'; import expectLibrary from '../third_party/index'; + export const expect = expectLibrary; export * as mock from 'jest-mock'; -import * as am from '../third_party/asymmetricMatchers'; -import * as mu from 'jest-matcher-utils'; export const asymmetricMatchers = { any: am.any, diff --git a/packages/playwright/bundles/expect/third_party/asymmetricMatchers.ts b/packages/playwright/bundles/expect/third_party/asymmetricMatchers.ts index 4e7a3402c90e6..a779f8be35076 100644 --- a/packages/playwright/bundles/expect/third_party/asymmetricMatchers.ts +++ b/packages/playwright/bundles/expect/third_party/asymmetricMatchers.ts @@ -15,7 +15,9 @@ import { } from '@jest/expect-utils'; import * as matcherUtils from 'jest-matcher-utils'; import { pluralize } from 'jest-util'; + import { getCustomEqualityTesters, getState } from './jestMatchersObject'; + import type { AsymmetricMatcher as AsymmetricMatcherInterface, MatcherContext, diff --git a/packages/playwright/bundles/expect/third_party/extractExpectedAssertionsErrors.ts b/packages/playwright/bundles/expect/third_party/extractExpectedAssertionsErrors.ts index 1be9b4dce921a..d50c01c69251d 100644 --- a/packages/playwright/bundles/expect/third_party/extractExpectedAssertionsErrors.ts +++ b/packages/playwright/bundles/expect/third_party/extractExpectedAssertionsErrors.ts @@ -12,7 +12,9 @@ import { matcherHint, pluralize, } from 'jest-matcher-utils'; + import { getState, setState } from './jestMatchersObject'; + import type { Expect, ExpectedAssertionsErrors } from './types'; const resetAssertionsLocalState = () => { diff --git a/packages/playwright/bundles/expect/third_party/index.ts b/packages/playwright/bundles/expect/third_party/index.ts index 3935ab71e1f50..7d5e7bce0e623 100644 --- a/packages/playwright/bundles/expect/third_party/index.ts +++ b/packages/playwright/bundles/expect/third_party/index.ts @@ -9,6 +9,7 @@ import { equals, iterableEquality, subsetEquality } from '@jest/expect-utils'; import * as matcherUtils from 'jest-matcher-utils'; import { isPromise } from 'jest-util'; + import { any, anything, @@ -38,6 +39,7 @@ import spyMatchers from './spyMatchers'; import toThrowMatchers, { createMatcher as createThrowMatcher, } from './toThrowMatchers'; + import type { Expect, ExpectationResult, @@ -54,8 +56,8 @@ import type { export type { Tester, TesterContext } from '@jest/expect-utils'; export { AsymmetricMatcher } from './asymmetricMatchers'; export type { - AsyncExpectationResult, AsymmetricMatchers, + AsyncExpectationResult, BaseExpect, Expect, ExpectationResult, diff --git a/packages/playwright/bundles/expect/third_party/jestMatchersObject.ts b/packages/playwright/bundles/expect/third_party/jestMatchersObject.ts index 7a9a304b303dc..30879e11c1f9b 100644 --- a/packages/playwright/bundles/expect/third_party/jestMatchersObject.ts +++ b/packages/playwright/bundles/expect/third_party/jestMatchersObject.ts @@ -6,15 +6,17 @@ * */ -import type { Tester } from '@jest/expect-utils'; import { getType } from 'jest-get-type'; + import { AsymmetricMatcher } from './asymmetricMatchers'; + import type { Expect, MatcherState, MatchersObject, SyncExpectationResult, } from './types'; +import type { Tester } from '@jest/expect-utils'; // Global matchers object holds the list of available matchers and // the state, that can hold matcher specific values that change over time. diff --git a/packages/playwright/bundles/expect/third_party/matchers.ts b/packages/playwright/bundles/expect/third_party/matchers.ts index 5102b50c3262c..fac0446666f89 100644 --- a/packages/playwright/bundles/expect/third_party/matchers.ts +++ b/packages/playwright/bundles/expect/third_party/matchers.ts @@ -23,7 +23,7 @@ import { getType, isPrimitive } from 'jest-get-type'; import { DIM_COLOR, EXPECTED_COLOR, - type MatcherHintOptions, + RECEIVED_COLOR, SUGGEST_TO_CONTAIN_EQUAL, ensureExpectedIsNonNegativeInteger, @@ -36,8 +36,9 @@ import { printExpected, printReceived, printWithType, - stringify, + stringify } from 'jest-matcher-utils'; + import { printCloseTo, printExpectedConstructorName, @@ -48,7 +49,9 @@ import { printReceivedStringContainExpectedResult, printReceivedStringContainExpectedSubstring, } from './print'; + import type { MatchersObject } from './types'; +import type { MatcherHintOptions } from 'jest-matcher-utils'; // Omit colon and one or more spaces, so can call getLabelPrinter. const EXPECTED_LABEL = 'Expected'; diff --git a/packages/playwright/bundles/expect/third_party/spyMatchers.ts b/packages/playwright/bundles/expect/third_party/spyMatchers.ts index ac74fd8d914fc..038351bc06299 100644 --- a/packages/playwright/bundles/expect/third_party/spyMatchers.ts +++ b/packages/playwright/bundles/expect/third_party/spyMatchers.ts @@ -10,7 +10,7 @@ import { getType, isPrimitive } from 'jest-get-type'; import { DIM_COLOR, EXPECTED_COLOR, - type MatcherHintOptions, + RECEIVED_COLOR, diff, ensureExpectedIsNonNegativeInteger, @@ -20,14 +20,17 @@ import { printExpected, printReceived, printWithType, - stringify, + stringify } from 'jest-matcher-utils'; + import { getCustomEqualityTesters } from './jestMatchersObject'; + import type { MatcherFunction, MatchersObject, SyncExpectationResult, } from './types'; +import type { MatcherHintOptions } from 'jest-matcher-utils'; /* eslint-disable eqeqeq */ diff --git a/packages/playwright/bundles/expect/third_party/toThrowMatchers.ts b/packages/playwright/bundles/expect/third_party/toThrowMatchers.ts index 5a2bb9dcad2f0..bcb869737996d 100644 --- a/packages/playwright/bundles/expect/third_party/toThrowMatchers.ts +++ b/packages/playwright/bundles/expect/third_party/toThrowMatchers.ts @@ -9,16 +9,17 @@ import { isError } from '@jest/expect-utils'; import { EXPECTED_COLOR, - type MatcherHintOptions, + RECEIVED_COLOR, matcherErrorMessage, matcherHint, printDiffOrStringify, printExpected, printReceived, - printWithType, + printWithType } from 'jest-matcher-utils'; import { formatStackTrace, separateMessageFromStack } from 'jest-message-util'; + import { printExpectedConstructorName, printExpectedConstructorNameNot, @@ -27,12 +28,14 @@ import { printReceivedStringContainExpectedResult, printReceivedStringContainExpectedSubstring, } from './print'; + import type { ExpectationResult, MatcherFunction, MatchersObject, SyncExpectationResult, } from './types'; +import type { MatcherHintOptions } from 'jest-matcher-utils'; /* eslint-disable eqeqeq */ diff --git a/packages/playwright/bundles/expect/third_party/types.ts b/packages/playwright/bundles/expect/third_party/types.ts index abaa3a3b69472..65660ff38bf4a 100644 --- a/packages/playwright/bundles/expect/third_party/types.ts +++ b/packages/playwright/bundles/expect/third_party/types.ts @@ -6,9 +6,9 @@ * */ +import type { INTERNAL_MATCHER_FLAG } from './jestMatchersObject'; import type { EqualsFunction, Tester } from '@jest/expect-utils'; import type * as jestMatcherUtils from 'jest-matcher-utils'; -import type { INTERNAL_MATCHER_FLAG } from './jestMatchersObject'; export type SyncExpectationResult = { pass: boolean; diff --git a/packages/playwright/bundles/utils/src/utilsBundleImpl.ts b/packages/playwright/bundles/utils/src/utilsBundleImpl.ts index 6cd35e288554c..69282957634c3 100644 --- a/packages/playwright/bundles/utils/src/utilsBundleImpl.ts +++ b/packages/playwright/bundles/utils/src/utilsBundleImpl.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +/* eslint-disable import/order */ + import json5Library from 'json5'; export const json5 = json5Library; diff --git a/packages/playwright/package.json b/packages/playwright/package.json index a525d5deee4df..c777298ad534b 100644 --- a/packages/playwright/package.json +++ b/packages/playwright/package.json @@ -1,6 +1,6 @@ { "name": "playwright", - "version": "1.50.0-next", + "version": "1.51.1", "description": "A high-level API to automate web browsers", "repository": { "type": "git", @@ -56,7 +56,7 @@ }, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.50.0-next" + "playwright-core": "1.51.1" }, "optionalDependencies": { "fsevents": "2.3.2" diff --git a/packages/playwright/src/DEPS.list b/packages/playwright/src/DEPS.list index 200d75de1ad1f..25ca70ff1877a 100644 --- a/packages/playwright/src/DEPS.list +++ b/packages/playwright/src/DEPS.list @@ -8,7 +8,11 @@ common/ [index.ts] @testIsomorphic/** +./prompt.ts ./worker/testTracing.ts [internalsForTest.ts] ** + +[prompt.ts] +./transform/babelBundle.ts diff --git a/packages/playwright/src/common/config.ts b/packages/playwright/src/common/config.ts index 443cb583196fb..0c1a7b73476db 100644 --- a/packages/playwright/src/common/config.ts +++ b/packages/playwright/src/common/config.ts @@ -15,14 +15,16 @@ */ import fs from 'fs'; -import path from 'path'; import os from 'os'; -import type { Config, Fixtures, Project, ReporterDescription } from '../../types/test'; -import type { Location } from '../../types/testReporter'; -import type { TestRunnerPluginRegistration } from '../plugins'; +import path from 'path'; + import { getPackageJsonPath, mergeObjects } from '../util'; + +import type { Config, Fixtures, Metadata, Project, ReporterDescription } from '../../types/test'; +import type { TestRunnerPluginRegistration } from '../plugins'; import type { Matcher } from '../util'; import type { ConfigCLIOverrides } from './ipc'; +import type { Location } from '../../types/testReporter'; import type { FullConfig, FullProject } from '../../types/testReporter'; export type ConfigLocation = { @@ -46,6 +48,7 @@ export class FullConfigInternal { readonly plugins: TestRunnerPluginRegistration[]; readonly projects: FullProjectInternal[] = []; readonly singleTSConfigPath?: string; + readonly captureGitInfo: Config['captureGitInfo']; cliArgs: string[] = []; cliGrep: string | undefined; cliGrepInvert: string | undefined; @@ -62,7 +65,7 @@ export class FullConfigInternal { globalSetups: string[] = []; globalTeardowns: string[] = []; - constructor(location: ConfigLocation, userConfig: Config, configCLIOverrides: ConfigCLIOverrides) { + constructor(location: ConfigLocation, userConfig: Config, configCLIOverrides: ConfigCLIOverrides, metadata?: Metadata) { if (configCLIOverrides.projects && userConfig.projects) throw new Error(`Cannot use --browser option when configuration file defines projects. Specify browserName in the projects instead.`); @@ -75,10 +78,15 @@ export class FullConfigInternal { const privateConfiguration = (userConfig as any)['@playwright/test']; this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p })); this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig); + this.captureGitInfo = userConfig.captureGitInfo; this.globalSetups = (Array.isArray(userConfig.globalSetup) ? userConfig.globalSetup : [userConfig.globalSetup]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined); this.globalTeardowns = (Array.isArray(userConfig.globalTeardown) ? userConfig.globalTeardown : [userConfig.globalTeardown]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined); + // Make sure we reuse same metadata instance between FullConfigInternal instances, + // so that plugins such as gitCommitInfoPlugin can populate metadata once. + userConfig.metadata = userConfig.metadata || {}; + this.config = { configFile: resolvedConfigFile, rootDir: pathResolve(configDir, userConfig.testDir) || configDir, @@ -86,14 +94,14 @@ export class FullConfigInternal { fullyParallel: takeFirst(configCLIOverrides.fullyParallel, userConfig.fullyParallel, false), globalSetup: this.globalSetups[0] ?? null, globalTeardown: this.globalTeardowns[0] ?? null, - globalTimeout: takeFirst(configCLIOverrides.globalTimeout, userConfig.globalTimeout, 0), + globalTimeout: takeFirst(configCLIOverrides.debug ? 0 : undefined, configCLIOverrides.globalTimeout, userConfig.globalTimeout, 0), grep: takeFirst(userConfig.grep, defaultGrep), grepInvert: takeFirst(userConfig.grepInvert, null), maxFailures: takeFirst(configCLIOverrides.debug ? 1 : undefined, configCLIOverrides.maxFailures, userConfig.maxFailures, 0), - metadata: takeFirst(userConfig.metadata, {}), + metadata: metadata ?? userConfig.metadata, preserveOutput: takeFirst(userConfig.preserveOutput, 'always'), reporter: takeFirst(configCLIOverrides.reporter, resolveReporters(userConfig.reporter, configDir), [[defaultReporter]]), - reportSlowTests: takeFirst(userConfig.reportSlowTests, { max: 5, threshold: 15000 }), + reportSlowTests: takeFirst(userConfig.reportSlowTests, { max: 5, threshold: 300_000 /* 5 minutes */ }), quiet: takeFirst(configCLIOverrides.quiet, userConfig.quiet, false), projects: [], shard: takeFirst(configCLIOverrides.shard, userConfig.shard, null), @@ -164,7 +172,7 @@ export class FullProjectInternal { readonly fullyParallel: boolean; readonly expect: Project['expect']; readonly respectGitIgnore: boolean; - readonly snapshotPathTemplate: string; + readonly snapshotPathTemplate: string | undefined; readonly ignoreSnapshots: boolean; id = ''; deps: FullProjectInternal[] = []; @@ -173,8 +181,7 @@ export class FullProjectInternal { constructor(configDir: string, config: Config, fullConfig: FullConfigInternal, projectConfig: Project, configCLIOverrides: ConfigCLIOverrides, packageJsonDir: string) { this.fullConfig = fullConfig; const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir); - const defaultSnapshotPathTemplate = '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{-projectName}{-snapshotSuffix}{ext}'; - this.snapshotPathTemplate = takeFirst(projectConfig.snapshotPathTemplate, config.snapshotPathTemplate, defaultSnapshotPathTemplate); + this.snapshotPathTemplate = takeFirst(projectConfig.snapshotPathTemplate, config.snapshotPathTemplate); this.project = { grep: takeFirst(projectConfig.grep, config.grep, defaultGrep), diff --git a/packages/playwright/src/common/configLoader.ts b/packages/playwright/src/common/configLoader.ts index 13d7eac1879a9..74ded63c72e08 100644 --- a/packages/playwright/src/common/configLoader.ts +++ b/packages/playwright/src/common/configLoader.ts @@ -14,19 +14,23 @@ * limitations under the License. */ -import * as fs from 'fs'; -import * as path from 'path'; -import { gracefullyProcessExitDoNotHang, isRegExp } from 'playwright-core/lib/utils'; -import type { ConfigCLIOverrides, SerializedConfig } from './ipc'; +import fs from 'fs'; +import path from 'path'; + +import { gracefullyProcessExitDoNotHang } from 'playwright-core/lib/utils'; +import { isRegExp } from 'playwright-core/lib/utils'; + import { requireOrImport, setSingleTSConfig, setTransformConfig } from '../transform/transform'; -import type { Config, Project } from '../../types/test'; import { errorWithFile, fileIsModule } from '../util'; -import type { ConfigLocation } from './config'; import { FullConfigInternal } from './config'; -import { addToCompilationCache } from '../transform/compilationCache'; import { configureESMLoader, configureESMLoaderTransformConfig, registerESMLoader } from './esmLoaderHost'; +import { addToCompilationCache } from '../transform/compilationCache'; import { execArgvWithExperimentalLoaderOptions, execArgvWithoutExperimentalLoaderOptions } from '../transform/esmUtils'; +import type { ConfigLocation } from './config'; +import type { ConfigCLIOverrides, SerializedConfig } from './ipc'; +import type { Config, Project } from '../../types/test'; + const kDefineConfigWasUsed = Symbol('defineConfigWasUsed'); export const defineConfig = (...configs: any[]) => { let result = configs[0]; @@ -87,7 +91,7 @@ export const defineConfig = (...configs: any[]) => { export async function deserializeConfig(data: SerializedConfig): Promise { if (data.compilationCache) addToCompilationCache(data.compilationCache); - return await loadConfig(data.location, data.configCLIOverrides); + return await loadConfig(data.location, data.configCLIOverrides, undefined, data.metadata ? JSON.parse(data.metadata) : undefined); } async function loadUserConfig(location: ConfigLocation): Promise { @@ -97,7 +101,7 @@ async function loadUserConfig(location: ConfigLocation): Promise { return object as Config; } -export async function loadConfig(location: ConfigLocation, overrides?: ConfigCLIOverrides, ignoreProjectDependencies = false): Promise { +export async function loadConfig(location: ConfigLocation, overrides?: ConfigCLIOverrides, ignoreProjectDependencies = false, metadata?: Config['metadata']): Promise { // 1. Setup tsconfig; configure ESM loader with tsconfig and compilation cache. setSingleTSConfig(overrides?.tsconfig); await configureESMLoader(); @@ -105,7 +109,7 @@ export async function loadConfig(location: ConfigLocation, overrides?: ConfigCLI // 2. Load and validate playwright config. const userConfig = await loadUserConfig(location); validateConfig(location.resolvedConfigFile || '', userConfig); - const fullConfig = new FullConfigInternal(location, userConfig, overrides || {}); + const fullConfig = new FullConfigInternal(location, userConfig, overrides || {}, metadata); fullConfig.defineConfigWasUsed = !!(userConfig as any)[kDefineConfigWasUsed]; if (ignoreProjectDependencies) { for (const project of fullConfig.projects) { @@ -240,8 +244,8 @@ function validateConfig(file: string, config: Config) { } if ('updateSnapshots' in config && config.updateSnapshots !== undefined) { - if (typeof config.updateSnapshots !== 'string' || !['all', 'none', 'missing'].includes(config.updateSnapshots)) - throw errorWithFile(file, `config.updateSnapshots must be one of "all", "none" or "missing"`); + if (typeof config.updateSnapshots !== 'string' || !['all', 'changed', 'missing', 'none'].includes(config.updateSnapshots)) + throw errorWithFile(file, `config.updateSnapshots must be one of "all", "changed", "missing" or "none"`); } if ('workers' in config && config.workers !== undefined) { @@ -250,6 +254,13 @@ function validateConfig(file: string, config: Config) { else if (typeof config.workers === 'string' && !config.workers.endsWith('%')) throw errorWithFile(file, `config.workers must be a number or percentage`); } + + if ('tsconfig' in config && config.tsconfig !== undefined) { + if (typeof config.tsconfig !== 'string') + throw errorWithFile(file, `config.tsconfig must be a string`); + if (!fs.existsSync(path.resolve(file, '..', config.tsconfig))) + throw errorWithFile(file, `config.tsconfig does not exist`); + } } function validateProject(file: string, project: Project, title: string) { diff --git a/packages/playwright/src/common/esmLoaderHost.ts b/packages/playwright/src/common/esmLoaderHost.ts index 9daa71107c32d..1c8ef09585799 100644 --- a/packages/playwright/src/common/esmLoaderHost.ts +++ b/packages/playwright/src/common/esmLoaderHost.ts @@ -15,9 +15,10 @@ */ import url from 'url'; + import { addToCompilationCache, serializeCompilationCache } from '../transform/compilationCache'; -import { singleTSConfig, transformConfig } from '../transform/transform'; import { PortTransport } from '../transform/portTransport'; +import { singleTSConfig, transformConfig } from '../transform/transform'; let loaderChannel: PortTransport | undefined; // Node.js < 20 diff --git a/packages/playwright/src/common/fixtures.ts b/packages/playwright/src/common/fixtures.ts index 6b50947ab5c7a..1c2421b9b1c8f 100644 --- a/packages/playwright/src/common/fixtures.ts +++ b/packages/playwright/src/common/fixtures.ts @@ -14,11 +14,13 @@ * limitations under the License. */ +import crypto from 'crypto'; + import { filterStackFile, formatLocation } from '../util'; -import * as crypto from 'crypto'; + +import type { FixturesWithLocation } from './config'; import type { Fixtures } from '../../types/test'; import type { Location } from '../../types/testReporter'; -import type { FixturesWithLocation } from './config'; export type FixtureScope = 'test' | 'worker'; type FixtureAuto = boolean | 'all-hooks-included'; diff --git a/packages/playwright/src/common/globals.ts b/packages/playwright/src/common/globals.ts index 746e1ec847874..41f912acb8f31 100644 --- a/packages/playwright/src/common/globals.ts +++ b/packages/playwright/src/common/globals.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import type { TestInfoImpl } from '../worker/testInfo'; import type { Suite } from './test'; +import type { TestInfoImpl } from '../worker/testInfo'; let currentTestInfoValue: TestInfoImpl | null = null; export function setCurrentTestInfo(testInfo: TestInfoImpl | null) { diff --git a/packages/playwright/src/common/ipc.ts b/packages/playwright/src/common/ipc.ts index 76ee996216516..d941d59b8b073 100644 --- a/packages/playwright/src/common/ipc.ts +++ b/packages/playwright/src/common/ipc.ts @@ -15,11 +15,13 @@ */ import util from 'util'; + import { serializeCompilationCache } from '../transform/compilationCache'; -import type { SerializedCompilationCache } from '../transform/compilationCache'; + import type { ConfigLocation, FullConfigInternal } from './config'; import type { ReporterDescription, TestInfoError, TestStatus } from '../../types/test'; import type { MatcherResultProperty } from '../matchers/matcherHint'; +import type { SerializedCompilationCache } from '../transform/compilationCache'; export type ConfigCLIOverrides = { debug?: boolean; @@ -49,6 +51,7 @@ export type SerializedConfig = { location: ConfigLocation; configCLIOverrides: ConfigCLIOverrides; compilationCache?: SerializedCompilationCache; + metadata?: string; }; export type ProcessInitParams = { @@ -109,6 +112,7 @@ export type StepEndPayload = { wallTime: number; // milliseconds since unix epoch error?: TestInfoErrorImpl; suggestedRebaseline?: string; + annotations: { type: string, description?: string }[]; }; export type TestEntry = { @@ -144,6 +148,11 @@ export function serializeConfig(config: FullConfigInternal, passCompilationCache configCLIOverrides: config.configCLIOverrides, compilationCache: passCompilationCache ? serializeCompilationCache() : undefined, }; + + try { + result.metadata = JSON.stringify(config.config.metadata); + } catch (error) {} + return result; } diff --git a/packages/playwright/src/common/poolBuilder.ts b/packages/playwright/src/common/poolBuilder.ts index cc1bc095c99a5..f975efe92f80d 100644 --- a/packages/playwright/src/common/poolBuilder.ts +++ b/packages/playwright/src/common/poolBuilder.ts @@ -15,11 +15,12 @@ */ import { FixturePool } from './fixtures'; +import { formatLocation } from '../util'; + +import type { FullProjectInternal } from './config'; import type { LoadError } from './fixtures'; import type { Suite, TestCase } from './test'; import type { TestTypeImpl } from './testType'; -import type { FullProjectInternal } from './config'; -import { formatLocation } from '../util'; import type { TestError } from '../../types/testReporter'; export class PoolBuilder { diff --git a/packages/playwright/src/common/process.ts b/packages/playwright/src/common/process.ts index a372139698af8..54dd2fe991973 100644 --- a/packages/playwright/src/common/process.ts +++ b/packages/playwright/src/common/process.ts @@ -14,12 +14,14 @@ * limitations under the License. */ -import type { EnvProducedPayload, ProcessInitParams, TestInfoErrorImpl } from './ipc'; import { startProfiling, stopProfiling } from 'playwright-core/lib/utils'; + import { serializeError } from '../util'; import { registerESMLoader } from './esmLoaderHost'; import { execArgvWithoutExperimentalLoaderOptions } from '../transform/esmUtils'; +import type { EnvProducedPayload, ProcessInitParams, TestInfoErrorImpl } from './ipc'; + export type ProtocolRequest = { id: number; method: string; diff --git a/packages/playwright/src/common/suiteUtils.ts b/packages/playwright/src/common/suiteUtils.ts index 81dc9d5465d4b..ab676548b5aeb 100644 --- a/packages/playwright/src/common/suiteUtils.ts +++ b/packages/playwright/src/common/suiteUtils.ts @@ -15,11 +15,14 @@ */ import path from 'path'; + import { calculateSha1, toPosixPath } from 'playwright-core/lib/utils'; -import type { Suite, TestCase } from './test'; + +import { createFileMatcher } from '../util'; + import type { FullProjectInternal } from './config'; +import type { Suite, TestCase } from './test'; import type { Matcher, TestFileFilter } from '../util'; -import { createFileMatcher } from '../util'; export function filterSuite(suite: Suite, suiteFilter: (suites: Suite) => boolean, testFilter: (test: TestCase) => boolean) { diff --git a/packages/playwright/src/common/test.ts b/packages/playwright/src/common/test.ts index 3e7fb30a1ae81..7b54f0c2911a3 100644 --- a/packages/playwright/src/common/test.ts +++ b/packages/playwright/src/common/test.ts @@ -14,14 +14,16 @@ * limitations under the License. */ -import type { FixturePool } from './fixtures'; -import type * as reporterTypes from '../../types/testReporter'; -import type { TestTypeImpl } from './testType'; import { rootTestType } from './testType'; -import type { Annotation, FixturesWithLocation, FullProjectInternal } from './config'; -import type { Location, FullProject } from '../../types/testReporter'; import { computeTestCaseOutcome } from '../isomorphic/teleReceiver'; +import type { Annotation, FixturesWithLocation, FullProjectInternal } from './config'; +import type { FixturePool } from './fixtures'; +import type { TestTypeImpl } from './testType'; +import type * as reporterTypes from '../../types/testReporter'; +import type { FullProject, Location } from '../../types/testReporter'; + + class Base { title: string; _only = false; diff --git a/packages/playwright/src/common/testLoader.ts b/packages/playwright/src/common/testLoader.ts index 6a8940ee192cb..690a09643d384 100644 --- a/packages/playwright/src/common/testLoader.ts +++ b/packages/playwright/src/common/testLoader.ts @@ -16,13 +16,15 @@ import path from 'path'; import util from 'util'; -import type { TestError } from '../../types/testReporter'; + +import * as esmLoaderHost from './esmLoaderHost'; import { isWorkerProcess, setCurrentlyLoadingFileSuite } from './globals'; import { Suite } from './test'; +import { startCollectingFileDeps, stopCollectingFileDeps } from '../transform/compilationCache'; import { requireOrImport } from '../transform/transform'; import { filterStackTrace } from '../util'; -import { startCollectingFileDeps, stopCollectingFileDeps } from '../transform/compilationCache'; -import * as esmLoaderHost from './esmLoaderHost'; + +import type { TestError } from '../../types/testReporter'; export const defaultTimeout = 30000; diff --git a/packages/playwright/src/common/testType.ts b/packages/playwright/src/common/testType.ts index 4c9e6d8f90719..565ed58321cb5 100644 --- a/packages/playwright/src/common/testType.ts +++ b/packages/playwright/src/common/testType.ts @@ -14,15 +14,19 @@ * limitations under the License. */ +import { errors } from 'playwright-core'; +import { getPackageManagerExecCommand, monotonicTime, raceAgainstDeadline, currentZone } from 'playwright-core/lib/utils'; + +import { currentTestInfo, currentlyLoadingFileSuite, setCurrentlyLoadingFileSuite } from './globals'; +import { Suite, TestCase } from './test'; import { expect } from '../matchers/expect'; -import { currentlyLoadingFileSuite, currentTestInfo, setCurrentlyLoadingFileSuite } from './globals'; -import { TestCase, Suite } from './test'; import { wrapFunctionWithLocation } from '../transform/transform'; + import type { FixturesWithLocation } from './config'; -import type { Fixtures, TestType, TestDetails } from '../../types/test'; +import type { Fixtures, TestDetails, TestStepInfo, TestType } from '../../types/test'; import type { Location } from '../../types/testReporter'; -import { getPackageManagerExecCommand, monotonicTime, raceAgainstDeadline, zones } from 'playwright-core/lib/utils'; -import { errors } from 'playwright-core'; +import type { TestInfoImpl } from '../worker/testInfo'; + const testTypeSymbol = Symbol('testType'); @@ -258,21 +262,31 @@ export class TestTypeImpl { suite._use.push({ fixtures, location }); } - async _step(expectation: 'pass'|'skip', title: string, body: () => T | Promise, options: {box?: boolean, location?: Location, timeout?: number } = {}): Promise { + _step(expectation: 'pass'|'skip', title: string, body: (step: TestStepInfo) => T | Promise, options: {box?: boolean, location?: Location, timeout?: number } = {}): Promise { const testInfo = currentTestInfo(); if (!testInfo) throw new Error(`test.step() can only be called from a test`); - if (expectation === 'skip') { - const step = testInfo._addStep({ category: 'test.step.skip', title, location: options.location, box: options.box }); - step.complete({}); - return undefined as T; - } + return testInfo._floatingPromiseScope.wrapPromiseAPIResult(this._stepInternal(expectation, testInfo, title, body, options)); + } + + private async _stepInternal(expectation: 'pass'|'skip', testInfo: TestInfoImpl, title: string, body: (step: TestStepInfo) => T | Promise, options: {box?: boolean, location?: Location, timeout?: number } = {}): Promise { const step = testInfo._addStep({ category: 'test.step', title, location: options.location, box: options.box }); - return await zones.run('stepZone', step, async () => { + return await currentZone().with('stepZone', step).run(async () => { try { - const result = await raceAgainstDeadline(async () => body(), options.timeout ? monotonicTime() + options.timeout : 0); + let result: Awaited>> | undefined = undefined; + result = await raceAgainstDeadline(async () => { + try { + return await step.info._runStepBody(expectation === 'skip', body); + } catch (e) { + // If the step timed out, the test fixtures will tear down, which in turn + // will abort unfinished actions in the step body. Record such errors here. + if (result?.timedOut) + testInfo._failWithError(e); + throw e; + } + }, options.timeout ? monotonicTime() + options.timeout : 0); if (result.timedOut) - throw new errors.TimeoutError(`Step timeout ${options.timeout}ms exceeded.`); + throw new errors.TimeoutError(`Step timeout of ${options.timeout}ms exceeded.`); step.complete({}); return result.result; } catch (error) { diff --git a/packages/playwright/src/fsWatcher.ts b/packages/playwright/src/fsWatcher.ts index 53e6849b1a733..4078e4f9945c7 100644 --- a/packages/playwright/src/fsWatcher.ts +++ b/packages/playwright/src/fsWatcher.ts @@ -15,6 +15,7 @@ */ import { chokidar } from './utilsBundle'; + import type { FSWatcher } from 'chokidar'; export type FSEvent = { event: 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir', file: string }; diff --git a/packages/playwright/src/index.ts b/packages/playwright/src/index.ts index 83913c18dc9c1..a8c128694edf5 100644 --- a/packages/playwright/src/index.ts +++ b/packages/playwright/src/index.ts @@ -14,21 +14,27 @@ * limitations under the License. */ -import * as fs from 'fs'; -import * as path from 'path'; -import type { APIRequestContext, BrowserContext, Browser, BrowserContextOptions, LaunchOptions, Page, Tracing, Video } from 'playwright-core'; +import fs from 'fs'; +import path from 'path'; + import * as playwrightLibrary from 'playwright-core'; -import { createGuid, debugMode, addInternalStackPrefix, isString, asLocator, jsonStringifyForceASCII, zones } from 'playwright-core/lib/utils'; -import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, ScreenshotMode, TestInfo, TestType, VideoMode } from '../types/test'; -import type { TestInfoImpl, TestStepInternal } from './worker/testInfo'; +import { setBoxedStackPrefixes, asLocator, createGuid, currentZone, debugMode, isString, jsonStringifyForceASCII } from 'playwright-core/lib/utils'; + +import { currentTestInfo } from './common/globals'; import { rootTestType } from './common/testType'; +import { attachErrorPrompts } from './prompt'; + +import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, ScreenshotMode, TestInfo, TestType, VideoMode } from '../types/test'; import type { ContextReuseMode } from './common/config'; +import type { TestInfoImpl, TestStepInternal } from './worker/testInfo'; import type { ApiCallData, ClientInstrumentation, ClientInstrumentationListener } from '../../playwright-core/src/client/clientInstrumentation'; -import { currentTestInfo } from './common/globals'; +import type { Playwright as PlaywrightImpl } from '../../playwright-core/src/client/playwright'; +import type { APIRequestContext, Browser, BrowserContext, BrowserContextOptions, LaunchOptions, Page, Tracing, Video } from 'playwright-core'; + export { expect } from './matchers/expect'; export const _baseTest: TestType<{}, {}> = rootTestType.test; -addInternalStackPrefix(path.dirname(require.resolve('../package.json'))); +setBoxedStackPrefixes([path.dirname(require.resolve('../package.json'))]); if ((process as any)['__pw_initiator__']) { const originalStackTraceLimit = Error.stackTraceLimit; @@ -50,6 +56,7 @@ type TestFixtures = PlaywrightTestArgs & PlaywrightTestOptions & { }; type WorkerFixtures = PlaywrightWorkerArgs & PlaywrightWorkerOptions & { + playwright: PlaywrightImpl; _browserOptions: LaunchOptions; _optionContextReuseMode: ContextReuseMode, _optionConnectOptions: PlaywrightWorkerOptions['connectOptions'], @@ -76,18 +83,16 @@ const playwrightFixtures: Fixtures = ({ const options: LaunchOptions = { handleSIGINT: false, ...launchOptions, + tracesDir: tracing().tracesDir(), }; if (headless !== undefined) options.headless = headless; if (channel !== undefined) options.channel = channel; - options.tracesDir = tracing().tracesDir(); - for (const browserType of [playwright.chromium, playwright.firefox, playwright.webkit, playwright._bidiChromium, playwright._bidiFirefox]) - (browserType as any)._defaultLaunchOptions = options; + playwright._defaultLaunchOptions = options; await use(options); - for (const browserType of [playwright.chromium, playwright.firefox, playwright.webkit, playwright._bidiChromium, playwright._bidiFirefox]) - (browserType as any)._defaultLaunchOptions = undefined; + playwright._defaultLaunchOptions = undefined; }, { scope: 'worker', auto: true, box: true }], browser: [async ({ playwright, browserName, _browserOptions, connectOptions, _reuseContext }, use, testInfo) => { @@ -230,21 +235,14 @@ const playwrightFixtures: Fixtures = ({ testInfo.snapshotSuffix = process.platform; if (debugMode()) (testInfo as TestInfoImpl)._setDebugMode(); - for (const browserType of [playwright.chromium, playwright.firefox, playwright.webkit]) { - (browserType as any)._defaultContextOptions = _combinedContextOptions; - (browserType as any)._defaultContextTimeout = actionTimeout || 0; - (browserType as any)._defaultContextNavigationTimeout = navigationTimeout || 0; - } - (playwright.request as any)._defaultContextOptions = { ..._combinedContextOptions }; - (playwright.request as any)._defaultContextOptions.tracesDir = tracing().tracesDir(); - (playwright.request as any)._defaultContextOptions.timeout = actionTimeout || 0; + + playwright._defaultContextOptions = _combinedContextOptions; + playwright._defaultContextTimeout = actionTimeout || 0; + playwright._defaultContextNavigationTimeout = navigationTimeout || 0; await use(); - (playwright.request as any)._defaultContextOptions = undefined; - for (const browserType of [playwright.chromium, playwright.firefox, playwright.webkit]) { - (browserType as any)._defaultContextOptions = undefined; - (browserType as any)._defaultContextTimeout = undefined; - (browserType as any)._defaultContextNavigationTimeout = undefined; - } + playwright._defaultContextOptions = undefined; + playwright._defaultContextTimeout = undefined; + playwright._defaultContextNavigationTimeout = undefined; }, { auto: 'all-hooks-included', title: 'context configuration', box: true } as any], _setupArtifacts: [async ({ playwright, screenshot }, use, testInfo) => { @@ -263,7 +261,7 @@ const playwrightFixtures: Fixtures = ({ // Some special calls do not get into steps. if (!testInfo || data.apiName.includes('setTestIdAttribute') || data.apiName === 'tracing.groupEnd') return; - const zone = zones.zoneData('stepZone'); + const zone = currentZone().data('stepZone'); if (zone && zone.category === 'expect') { // Display the internal locator._expect call under the name of the enclosing expect call, // and connect it to the existing expect step. @@ -324,7 +322,6 @@ const playwrightFixtures: Fixtures = ({ clientInstrumentation.removeListener(csiListener); await artifactsRecorder.didFinishTest(); - }, { auto: 'all-hooks-included', title: 'trace recording', box: true, timeout: 0 } as any], _contextFactory: [async ({ browser, video, _reuseContext, _combinedContextOptions /** mitigate dep-via-auto lack of traceability */ }, use, testInfo) => { @@ -451,7 +448,6 @@ const playwrightFixtures: Fixtures = ({ }); type ScreenshotOption = PlaywrightWorkerOptions['screenshot'] | undefined; -type Playwright = PlaywrightWorkerArgs['playwright']; function normalizeVideoMode(video: VideoMode | 'retry-with-video' | { mode: VideoMode } | undefined): VideoMode { if (!video) @@ -473,7 +469,7 @@ function normalizeScreenshotMode(screenshot: ScreenshotOption): ScreenshotMode { } function attachConnectedHeaderIfNeeded(testInfo: TestInfo, browser: Browser | null) { - const connectHeaders: { name: string, value: string }[] | undefined = (browser as any)?._connectHeaders; + const connectHeaders: { name: string, value: string }[] | undefined = (browser as any)?._connection.headers; if (!connectHeaders) return; for (const header of connectHeaders) { @@ -523,54 +519,132 @@ function connectOptionsFromEnv() { }; } +type SnapshotRecorderMode = 'on' | 'off' | 'only-on-failure' | 'on-first-failure'; + +class SnapshotRecorder { + private _ordinal = 0; + private _temporary: string[] = []; + private _snapshottedSymbol = Symbol('snapshotted'); + + constructor( + private _artifactsRecorder: ArtifactsRecorder, + private _mode: SnapshotRecorderMode, + private _name: string, + private _contentType: string, + private _extension: string, + private _doSnapshot: (page: Page, path: string) => Promise) { + } + + fixOrdinal() { + // Since beforeAll(s), test and afterAll(s) reuse the same TestInfo, make sure we do not + // overwrite previous screenshots. + this._ordinal = this.testInfo.attachments.filter(a => a.name === this._name).length; + } + + private shouldCaptureUponFinish() { + return this._mode === 'on' || + (this._mode === 'only-on-failure' && this.testInfo._isFailure()) || + (this._mode === 'on-first-failure' && this.testInfo._isFailure() && this.testInfo.retry === 0); + } + + async maybeCapture() { + if (!this.shouldCaptureUponFinish()) + return; + + await Promise.all(this._artifactsRecorder._playwright._allPages().map(page => this._snapshotPage(page, false))); + } + + async persistTemporary() { + if (this.shouldCaptureUponFinish()) { + await Promise.all(this._temporary.map(async file => { + try { + const path = this._createAttachmentPath(); + await fs.promises.rename(file, path); + this._attach(path); + } catch { + } + })); + } + } + + async captureTemporary(context: BrowserContext) { + if (this._mode === 'on' || this._mode === 'only-on-failure' || (this._mode === 'on-first-failure' && this.testInfo.retry === 0)) + await Promise.all(context.pages().map(page => this._snapshotPage(page, true))); + } + + private _attach(screenshotPath: string) { + this.testInfo.attachments.push({ name: this._name, path: screenshotPath, contentType: this._contentType }); + } + + private _createAttachmentPath() { + const testFailed = this.testInfo._isFailure(); + const index = this._ordinal + 1; + ++this._ordinal; + const path = this.testInfo.outputPath(`test-${testFailed ? 'failed' : 'finished'}-${index}${this._extension}`); + return path; + } + + private _createTemporaryArtifact(...name: string[]) { + const file = path.join(this._artifactsRecorder._artifactsDir, ...name); + return file; + } + + private async _snapshotPage(page: Page, temporary: boolean) { + if ((page as any)[this._snapshottedSymbol]) + return; + (page as any)[this._snapshottedSymbol] = true; + try { + const path = temporary ? this._createTemporaryArtifact(createGuid() + this._extension) : this._createAttachmentPath(); + await this._doSnapshot(page, path); + if (temporary) + this._temporary.push(path); + else + this._attach(path); + } catch { + // snapshot may fail, just ignore. + } + } + + private get testInfo(): TestInfoImpl { + return this._artifactsRecorder._testInfo; + } +} + class ArtifactsRecorder { - private _testInfo!: TestInfoImpl; - private _playwright: Playwright; - private _artifactsDir: string; - private _screenshotMode: ScreenshotMode; - private _screenshotOptions: { mode: ScreenshotMode } & Pick | undefined; - private _temporaryScreenshots: string[] = []; - private _temporaryArtifacts: string[] = []; + _testInfo!: TestInfoImpl; + _playwright: PlaywrightImpl; + _artifactsDir: string; private _reusedContexts = new Set(); - private _screenshotOrdinal = 0; - private _screenshottedSymbol: symbol; private _startedCollectingArtifacts: symbol; - constructor(playwright: Playwright, artifactsDir: string, screenshot: ScreenshotOption) { + private _screenshotRecorder: SnapshotRecorder; + private _pageSnapshot: string | undefined; + private _sourceCache: Map = new Map(); + + constructor(playwright: PlaywrightImpl, artifactsDir: string, screenshot: ScreenshotOption) { this._playwright = playwright; this._artifactsDir = artifactsDir; - this._screenshotMode = normalizeScreenshotMode(screenshot); - this._screenshotOptions = typeof screenshot === 'string' ? undefined : screenshot; - this._screenshottedSymbol = Symbol('screenshotted'); + const screenshotOptions = typeof screenshot === 'string' ? undefined : screenshot; this._startedCollectingArtifacts = Symbol('startedCollectingArtifacts'); - } - private _createTemporaryArtifact(...name: string[]) { - const file = path.join(this._artifactsDir, ...name); - this._temporaryArtifacts.push(file); - return file; + this._screenshotRecorder = new SnapshotRecorder(this, normalizeScreenshotMode(screenshot), 'screenshot', 'image/png', '.png', async (page, path) => { + await page.screenshot({ ...screenshotOptions, timeout: 5000, path, caret: 'initial' }); + }); } async willStartTest(testInfo: TestInfoImpl) { this._testInfo = testInfo; testInfo._onDidFinishTestFunction = () => this.didFinishTestFunction(); - // Since beforeAll(s), test and afterAll(s) reuse the same TestInfo, make sure we do not - // overwrite previous screenshots. - this._screenshotOrdinal = testInfo.attachments.filter(a => a.name === 'screenshot').length; + this._screenshotRecorder.fixOrdinal(); // Process existing contexts. - for (const browserType of [this._playwright.chromium, this._playwright.firefox, this._playwright.webkit]) { - const promises: (Promise | undefined)[] = []; - const existingContexts = Array.from((browserType as any)._contexts) as BrowserContext[]; - for (const context of existingContexts) { - if ((context as any)[kIsReusedContext]) - this._reusedContexts.add(context); - else - promises.push(this.didCreateBrowserContext(context)); - } - await Promise.all(promises); - } + await Promise.all(this._playwright._allContexts().map(async context => { + if ((context as any)[kIsReusedContext]) + this._reusedContexts.add(context); + else + await this.didCreateBrowserContext(context); + })); { const existingApiRequests: APIRequestContext[] = Array.from((this._playwright.request as any)._contexts as Set); await Promise.all(existingApiRequests.map(c => this.didCreateRequestContext(c))); @@ -587,10 +661,15 @@ class ArtifactsRecorder { if (this._reusedContexts.has(context)) return; await this._stopTracing(context.tracing); - if (this._screenshotMode === 'on' || this._screenshotMode === 'only-on-failure' || (this._screenshotMode === 'on-first-failure' && this._testInfo.retry === 0)) { - // Capture screenshot for now. We'll know whether we have to preserve them - // after the test finishes. - await Promise.all(context.pages().map(page => this._screenshotPage(page, true))); + + await this._screenshotRecorder.captureTemporary(context); + + if (!process.env.PLAYWRIGHT_NO_COPY_PROMPT && this._testInfo.errors.length > 0) { + try { + const page = context.pages()[0]; + // TODO: maybe capture snapshot when the error is created, so it's from the right page and right time + this._pageSnapshot ??= await page?.locator('body').ariaSnapshot({ timeout: 5000 }); + } catch {} } } @@ -604,26 +683,14 @@ class ArtifactsRecorder { await this._stopTracing(tracing); } - private _shouldCaptureScreenshotUponFinish() { - return this._screenshotMode === 'on' || - (this._screenshotMode === 'only-on-failure' && this._testInfo._isFailure()) || - (this._screenshotMode === 'on-first-failure' && this._testInfo._isFailure() && this._testInfo.retry === 0); - } - async didFinishTestFunction() { - if (this._shouldCaptureScreenshotUponFinish()) - await this._screenshotOnTestFailure(); + await this._screenshotRecorder.maybeCapture(); } async didFinishTest() { - const captureScreenshots = this._shouldCaptureScreenshotUponFinish(); - if (captureScreenshots) - await this._screenshotOnTestFailure(); - - let leftoverContexts: BrowserContext[] = []; - for (const browserType of [this._playwright.chromium, this._playwright.firefox, this._playwright.webkit]) - leftoverContexts.push(...(browserType as any)._contexts); - leftoverContexts = leftoverContexts.filter(context => !this._reusedContexts.has(context)); + await this.didFinishTestFunction(); + + const leftoverContexts = this._playwright._allContexts().filter(context => !this._reusedContexts.has(context)); const leftoverApiRequests: APIRequestContext[] = Array.from((this._playwright.request as any)._contexts as Set); // Collect traces/screenshots for remaining contexts. @@ -634,55 +701,8 @@ class ArtifactsRecorder { await this._stopTracing(tracing); }))); - // Attach temporary screenshots for contexts closed before collecting the test trace. - if (captureScreenshots) { - for (const file of this._temporaryScreenshots) { - try { - const screenshotPath = this._createScreenshotAttachmentPath(); - await fs.promises.rename(file, screenshotPath); - this._attachScreenshot(screenshotPath); - } catch { - } - } - } - } - - private _createScreenshotAttachmentPath() { - const testFailed = this._testInfo._isFailure(); - const index = this._screenshotOrdinal + 1; - ++this._screenshotOrdinal; - const screenshotPath = this._testInfo.outputPath(`test-${testFailed ? 'failed' : 'finished'}-${index}.png`); - return screenshotPath; - } - - private async _screenshotPage(page: Page, temporary: boolean) { - if ((page as any)[this._screenshottedSymbol]) - return; - (page as any)[this._screenshottedSymbol] = true; - try { - const screenshotPath = temporary ? this._createTemporaryArtifact(createGuid() + '.png') : this._createScreenshotAttachmentPath(); - // Pass caret=initial to avoid any evaluations that might slow down the screenshot - // and let the page modify itself from the problematic state it had at the moment of failure. - await page.screenshot({ ...this._screenshotOptions, timeout: 5000, path: screenshotPath, caret: 'initial' }); - if (temporary) - this._temporaryScreenshots.push(screenshotPath); - else - this._attachScreenshot(screenshotPath); - } catch { - // Screenshot may fail, just ignore. - } - } - - private _attachScreenshot(screenshotPath: string) { - this._testInfo.attachments.push({ name: 'screenshot', path: screenshotPath, contentType: 'image/png' }); - } - - private async _screenshotOnTestFailure() { - const contexts: BrowserContext[] = []; - for (const browserType of [this._playwright.chromium, this._playwright.firefox, this._playwright.webkit]) - contexts.push(...(browserType as any)._contexts); - const pages = contexts.map(ctx => ctx.pages()).flat(); - await Promise.all(pages.map(page => this._screenshotPage(page, false))); + await this._screenshotRecorder.persistTemporary(); + await attachErrorPrompts(this._testInfo, this._sourceCache, this._pageSnapshot); } private async _startTraceChunkOnContextCreation(tracing: Tracing) { @@ -709,7 +729,7 @@ class ArtifactsRecorder { return; (tracing as any)[this._startedCollectingArtifacts] = true; if (this._testInfo._tracing.traceOptions() && (tracing as any)[kTracingStarted]) - await tracing.stopChunk({ path: this._testInfo._tracing.generateNextTraceRecordingPath() }); + await tracing.stopChunk({ path: this._testInfo._tracing.maybeGenerateNextTraceRecordingPath() }); } } diff --git a/packages/playwright/src/internalsForTest.ts b/packages/playwright/src/internalsForTest.ts index c0d2cbd95f295..129f9e858d3d1 100644 --- a/packages/playwright/src/internalsForTest.ts +++ b/packages/playwright/src/internalsForTest.ts @@ -15,6 +15,7 @@ */ import path from 'path'; + import { fileDependenciesForTest } from './transform/compilationCache'; export function fileDependencies() { diff --git a/packages/playwright/src/isomorphic/teleReceiver.ts b/packages/playwright/src/isomorphic/teleReceiver.ts index 1d41b793cd80e..29b1beb74d70b 100644 --- a/packages/playwright/src/isomorphic/teleReceiver.ts +++ b/packages/playwright/src/isomorphic/teleReceiver.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import type { Annotation } from '../common/config'; import type { Metadata } from '../../types/test'; import type * as reporterTypes from '../../types/testReporter'; +import type { Annotation } from '../common/config'; import type { ReporterV2 } from '../reporters/reporterV2'; export type StringIntern = (s: string) => string; @@ -52,6 +52,7 @@ export type JsonProject = { testIgnore: JsonPattern[]; testMatch: JsonPattern[]; timeout: number; + use: { [key: string]: any }; }; export type JsonSuite = { @@ -109,6 +110,7 @@ export type JsonTestStepEnd = { duration: number; error?: reporterTypes.TestError; attachments?: number[]; // index of JsonTestResultEnd.attachments + annotations?: Annotation[]; }; export type JsonFullResult = { @@ -325,7 +327,7 @@ export class TeleReporterReceiver { dependencies: project.dependencies, teardown: project.teardown, snapshotDir: this._absolutePath(project.snapshotDir), - use: {}, + use: project.use, }; } @@ -546,6 +548,10 @@ class TeleTestStep implements reporterTypes.TestStep { get attachments() { return this._endPayload?.attachments?.map(index => this._result.attachments[index]) ?? []; } + + get annotations() { + return this._endPayload?.annotations ?? []; + } } export class TeleTestResult implements reporterTypes.TestResult { @@ -599,7 +605,7 @@ export const baseFullConfig: reporterTypes.FullConfig = { preserveOutput: 'always', projects: [], reporter: [[process.env.CI ? 'dot' : 'list']], - reportSlowTests: { max: 5, threshold: 15000 }, + reportSlowTests: { max: 5, threshold: 300_000 /* 5 minutes */ }, configFile: '', rootDir: '', quiet: false, diff --git a/packages/playwright/src/isomorphic/teleSuiteUpdater.ts b/packages/playwright/src/isomorphic/teleSuiteUpdater.ts index 6f86c50147776..7c4c14fae7395 100644 --- a/packages/playwright/src/isomorphic/teleSuiteUpdater.ts +++ b/packages/playwright/src/isomorphic/teleSuiteUpdater.ts @@ -16,8 +16,9 @@ import { TeleReporterReceiver, TeleSuite } from './teleReceiver'; import { statusEx } from './testTree'; -import type { ReporterV2 } from '../reporters/reporterV2'; + import type * as reporterTypes from '../../types/testReporter'; +import type { ReporterV2 } from '../reporters/reporterV2'; export type TeleSuiteUpdaterProgress = { total: number; diff --git a/packages/playwright/src/isomorphic/testServerConnection.ts b/packages/playwright/src/isomorphic/testServerConnection.ts index 22bdce30ff53b..f4caf62fae1f6 100644 --- a/packages/playwright/src/isomorphic/testServerConnection.ts +++ b/packages/playwright/src/isomorphic/testServerConnection.ts @@ -14,9 +14,10 @@ * limitations under the License. */ -import type { TestServerInterface, TestServerInterfaceEvents } from '@testIsomorphic/testServerInterface'; import * as events from './events'; +import type { TestServerInterface, TestServerInterfaceEvents } from '@testIsomorphic/testServerInterface'; + // -- Reuse boundary -- Everything below this line is reused in the vscode extension. export interface TestServerTransport { diff --git a/packages/playwright/src/isomorphic/testServerInterface.ts b/packages/playwright/src/isomorphic/testServerInterface.ts index 694610ecdd434..66136bab2e386 100644 --- a/packages/playwright/src/isomorphic/testServerInterface.ts +++ b/packages/playwright/src/isomorphic/testServerInterface.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import type * as reporterTypes from '../../types/testReporter'; import type { Event } from './events'; import type { JsonEvent } from './teleReceiver'; +import type * as reporterTypes from '../../types/testReporter'; // -- Reuse boundary -- Everything below this line is reused in the vscode extension. diff --git a/packages/playwright/src/isomorphic/types.d.ts b/packages/playwright/src/isomorphic/types.d.ts new file mode 100644 index 0000000000000..5f31b925a2e3f --- /dev/null +++ b/packages/playwright/src/isomorphic/types.d.ts @@ -0,0 +1,49 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type GitCommitInfo = { + shortHash: string; + hash: string; + subject: string; + body: string; + author: { + name: string; + email: string; + time: number; + }; + committer: { + name: string; + email: string + time: number; + }; + branch: string; +}; + +export type CIInfo = { + commitHref: string; + prHref?: string; + prTitle?: string; + prBaseHash?: string; + buildHref?: string; + commitHash?: string; + branch?: string; +}; + +export type MetadataWithCommitInfo = { + ci?: CIInfo; + gitCommit?: GitCommitInfo; + gitDiff?: string; +}; diff --git a/packages/playwright/src/isomorphic/util.ts b/packages/playwright/src/isomorphic/util.ts new file mode 100644 index 0000000000000..208b5f0cd1a3a --- /dev/null +++ b/packages/playwright/src/isomorphic/util.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const kTopLevelAttachmentPrefix = '_attach'; diff --git a/packages/playwright/src/loader/loaderMain.ts b/packages/playwright/src/loader/loaderMain.ts index 97befeea9d7c7..50bd380c7c376 100644 --- a/packages/playwright/src/loader/loaderMain.ts +++ b/packages/playwright/src/loader/loaderMain.ts @@ -14,15 +14,16 @@ * limitations under the License. */ -import type { SerializedConfig } from '../common/ipc'; import { deserializeConfig } from '../common/configLoader'; +import { incorporateCompilationCache } from '../common/esmLoaderHost'; +import { PoolBuilder } from '../common/poolBuilder'; import { ProcessRunner } from '../common/process'; -import type { FullConfigInternal } from '../common/config'; import { loadTestFile } from '../common/testLoader'; -import type { TestError } from '../../types/testReporter'; import { serializeCompilationCache } from '../transform/compilationCache'; -import { PoolBuilder } from '../common/poolBuilder'; -import { incorporateCompilationCache } from '../common/esmLoaderHost'; + +import type { TestError } from '../../types/testReporter'; +import type { FullConfigInternal } from '../common/config'; +import type { SerializedConfig } from '../common/ipc'; export class LoaderMain extends ProcessRunner { private _serializedConfig: SerializedConfig; diff --git a/packages/playwright/src/matchers/expect.ts b/packages/playwright/src/matchers/expect.ts index d382a4dbfd2ce..c472e50bbbf59 100644 --- a/packages/playwright/src/matchers/expect.ts +++ b/packages/playwright/src/matchers/expect.ts @@ -17,8 +17,11 @@ import { captureRawStack, createGuid, + currentZone, isString, pollAgainstDeadline } from 'playwright-core/lib/utils'; + +import { ExpectError, isJestError } from './matcherHint'; import { toBeAttached, toBeChecked, @@ -33,12 +36,12 @@ import { toBeVisible, toContainText, toHaveAccessibleDescription, - toHaveAccessibleName, toHaveAccessibleErrorMessage, + toHaveAccessibleName, toHaveAttribute, + toHaveCSS, toHaveClass, toHaveCount, - toHaveCSS, toHaveId, toHaveJSProperty, toHaveRole, @@ -49,20 +52,22 @@ import { toHaveValues, toPass } from './matchers'; -import { toMatchSnapshot, toHaveScreenshot, toHaveScreenshotStepTitle } from './toMatchSnapshot'; -import type { Expect, ExpectMatcherState } from '../../types/test'; -import { currentTestInfo } from '../common/globals'; -import { filteredStackTrace, trimLongString } from '../util'; +import { toMatchAriaSnapshot } from './toMatchAriaSnapshot'; +import { toHaveScreenshot, toHaveScreenshotStepTitle, toMatchSnapshot } from './toMatchSnapshot'; import { - expect as expectLibrary, INVERTED_COLOR, RECEIVED_COLOR, + expect as expectLibrary, printReceived, } from '../common/expectBundle'; -import { zones } from 'playwright-core/lib/utils'; +import { currentTestInfo } from '../common/globals'; +import { filteredStackTrace, trimLongString } from '../util'; import { TestInfoImpl } from '../worker/testInfo'; -import { ExpectError, isJestError } from './matcherHint'; -import { toMatchAriaSnapshot } from './toMatchAriaSnapshot'; + +import type { ExpectMatcherStateInternal } from './matchers'; +import type { Expect } from '../../types/test'; +import type { TestStepInfoImpl } from '../worker/testInfo'; + // #region // Mirrored from https://github.com/facebook/jest/blob/f13abff8df9a0e1148baf3584bcde6d1b479edc7/packages/expect/src/print.ts @@ -110,13 +115,13 @@ function createMatchers(actual: unknown, info: ExpectMetaInfo, prefix: string[]) return new Proxy(expectLibrary(actual), new ExpectMetaInfoProxyHandler(info, prefix)); } -const getCustomMatchersSymbol = Symbol('get custom matchers'); +const userMatchersSymbol = Symbol('userMatchers'); function qualifiedMatcherName(qualifier: string[], matcherName: string) { return qualifier.join(':') + '$' + matcherName; } -function createExpect(info: ExpectMetaInfo, prefix: string[], customMatchers: Record) { +function createExpect(info: ExpectMetaInfo, prefix: string[], userMatchers: Record) { const expectInstance: Expect<{}> = new Proxy(expectLibrary, { apply: function(target: any, thisArg: any, argumentsList: [unknown, ExpectMessage?]) { const [actual, messageOrOptions] = argumentsList; @@ -130,7 +135,7 @@ function createExpect(info: ExpectMetaInfo, prefix: string[], customMatchers: Re return createMatchers(actual, newInfo, prefix); }, - get: function(target: any, property: string | typeof getCustomMatchersSymbol) { + get: function(target: any, property: string | typeof userMatchersSymbol) { if (property === 'configure') return configure; @@ -139,27 +144,14 @@ function createExpect(info: ExpectMetaInfo, prefix: string[], customMatchers: Re const qualifier = [...prefix, createGuid()]; const wrappedMatchers: any = {}; - const extendedMatchers: any = { ...customMatchers }; for (const [name, matcher] of Object.entries(matchers)) { - wrappedMatchers[name] = function(...args: any[]) { - const { isNot, promise, utils } = this; - const newThis: ExpectMatcherState = { - isNot, - promise, - utils, - timeout: currentExpectTimeout() - }; - (newThis as any).equals = throwUnsupportedExpectMatcherError; - return (matcher as any).call(newThis, ...args); - }; + wrappedMatchers[name] = wrapPlaywrightMatcherToPassNiceThis(matcher); const key = qualifiedMatcherName(qualifier, name); wrappedMatchers[key] = wrappedMatchers[name]; Object.defineProperty(wrappedMatchers[key], 'name', { value: name }); - extendedMatchers[name] = wrappedMatchers[key]; } expectLibrary.extend(wrappedMatchers); - - return createExpect(info, qualifier, extendedMatchers); + return createExpect(info, qualifier, { ...userMatchers, ...matchers }); }; } @@ -169,8 +161,8 @@ function createExpect(info: ExpectMetaInfo, prefix: string[], customMatchers: Re }; } - if (property === getCustomMatchersSymbol) - return customMatchers; + if (property === userMatchersSymbol) + return userMatchers; if (property === 'poll') { return (actual: unknown, messageOrOptions?: ExpectMessage & { timeout?: number, intervals?: number[] }) => { @@ -197,12 +189,55 @@ function createExpect(info: ExpectMetaInfo, prefix: string[], customMatchers: Re newInfo.poll!.intervals = configuration._poll.intervals ?? newInfo.poll!.intervals; } } - return createExpect(newInfo, prefix, customMatchers); + return createExpect(newInfo, prefix, userMatchers); }; return expectInstance; } +// Expect wraps matchers, so there is no way to pass this information to the raw Playwright matcher. +// Rely on sync call sequence to seed each matcher call with the context. +type MatcherCallContext = { + expectInfo: ExpectMetaInfo; + testInfo: TestInfoImpl | null; + step?: TestStepInfoImpl; +}; + +let matcherCallContext: MatcherCallContext | undefined; + +function setMatcherCallContext(context: MatcherCallContext) { + matcherCallContext = context; +} + +function takeMatcherCallContext(): MatcherCallContext | undefined { + try { + return matcherCallContext; + } finally { + // Any subsequent matcher following the first is assumed to be an unsupported legacy asymmetric matcher. + // Lacking call context in these scenarios is not particularly important. + matcherCallContext = undefined; + } +} + +const defaultExpectTimeout = 5000; + +function wrapPlaywrightMatcherToPassNiceThis(matcher: any) { + return function(this: any, ...args: any[]) { + const { isNot, promise, utils } = this; + const context = takeMatcherCallContext(); + const timeout = context?.expectInfo.timeout ?? context?.testInfo?._projectInternal?.expect?.timeout ?? defaultExpectTimeout; + const newThis: ExpectMatcherStateInternal = { + isNot, + promise, + utils, + timeout, + _stepInfo: context?.step, + }; + (newThis as any).equals = throwUnsupportedExpectMatcherError; + return matcher.call(newThis, ...args); + }; +} + function throwUnsupportedExpectMatcherError() { throw new Error('It looks like you are using custom expect matchers that are not compatible with Playwright. See https://aka.ms/playwright/expect-compatibility'); } @@ -299,8 +334,7 @@ class ExpectMetaInfoProxyHandler implements ProxyHandler { } return (...args: any[]) => { const testInfo = currentTestInfo(); - // We assume that the matcher will read the current expect timeout the first thing. - setCurrentExpectConfigureTimeout(this._info.timeout); + setMatcherCallContext({ expectInfo: this._info, testInfo }); if (!testInfo) return matcher.call(target, ...args); @@ -329,6 +363,8 @@ class ExpectMetaInfoProxyHandler implements ProxyHandler { const jestError = isJestError(e) ? e : null; const error = jestError ? new ExpectError(jestError, customMessage, stackFrames) : e; if (jestError?.matcherResult.suggestedRebaseline) { + // NOTE: this is a workaround for the fact that we can't pass the suggested rebaseline + // for passing matchers. See toMatchAriaSnapshot for a counterpart. step.complete({ suggestedRebaseline: jestError?.matcherResult.suggestedRebaseline }); return; } @@ -344,10 +380,13 @@ class ExpectMetaInfoProxyHandler implements ProxyHandler { }; try { + setMatcherCallContext({ expectInfo: this._info, testInfo, step: step.info }); const callback = () => matcher.call(target, ...args); - const result = zones.run('stepZone', step, callback); - if (result instanceof Promise) - return result.then(finalizer).catch(reportStepError); + const result = currentZone().with('stepZone', step).run(callback); + if (result instanceof Promise) { + const promise = result.then(finalizer).catch(reportStepError); + return testInfo._floatingPromiseScope.wrapPromiseAPIResult(promise); + } finalizer(); return result; } catch (e) { @@ -360,7 +399,7 @@ class ExpectMetaInfoProxyHandler implements ProxyHandler { async function pollMatcher(qualifiedMatcherName: string, info: ExpectMetaInfo, prefix: string[], ...args: any[]) { const testInfo = currentTestInfo(); const poll = info.poll!; - const timeout = poll.timeout ?? currentExpectTimeout(); + const timeout = poll.timeout ?? info.timeout ?? testInfo?._projectInternal?.expect?.timeout ?? defaultExpectTimeout; const { deadline, timeoutMessage } = testInfo ? testInfo._deadlineForMatcher(timeout) : TestInfoImpl._defaultDeadlineForMatcher(timeout); const result = await pollAgainstDeadline(async () => { @@ -396,22 +435,6 @@ async function pollMatcher(qualifiedMatcherName: string, info: ExpectMetaInfo, p } } -let currentExpectConfigureTimeout: number | undefined; - -function setCurrentExpectConfigureTimeout(timeout: number | undefined) { - currentExpectConfigureTimeout = timeout; -} - -function currentExpectTimeout() { - if (currentExpectConfigureTimeout !== undefined) - return currentExpectConfigureTimeout; - const testInfo = currentTestInfo(); - let defaultExpectTimeout = testInfo?._projectInternal?.expect?.timeout; - if (typeof defaultExpectTimeout === 'undefined') - defaultExpectTimeout = 5000; - return defaultExpectTimeout; -} - function computeArgsSuffix(matcherName: string, args: any[]) { let value = ''; if (matcherName === 'toHaveScreenshot') @@ -424,7 +447,7 @@ export const expect: Expect<{}> = createExpect({}, [], {}).extend(customMatchers export function mergeExpects(...expects: any[]) { let merged = expect; for (const e of expects) { - const internals = e[getCustomMatchersSymbol]; + const internals = e[userMatchersSymbol]; if (!internals) // non-playwright expects mutate the global expect, so we don't need to do anything special continue; merged = merged.extend(internals); diff --git a/packages/playwright/src/matchers/matcherHint.ts b/packages/playwright/src/matchers/matcherHint.ts index dc4264d56b91c..316ecad6850ea 100644 --- a/packages/playwright/src/matchers/matcherHint.ts +++ b/packages/playwright/src/matchers/matcherHint.ts @@ -14,11 +14,12 @@ * limitations under the License. */ -import { colors } from 'playwright-core/lib/utilsBundle'; +import { stringifyStackFrames } from 'playwright-core/lib/utils'; +import { colors } from 'playwright-core/lib/utils'; + import type { ExpectMatcherState } from '../../types/test'; -import type { Locator } from 'playwright-core'; import type { StackFrame } from '@protocol/channels'; -import { stringifyStackFrames } from 'playwright-core/lib/utils'; +import type { Locator } from 'playwright-core'; export const kNoElementsFoundError = ''; diff --git a/packages/playwright/src/matchers/matchers.ts b/packages/playwright/src/matchers/matchers.ts index 9b43999cf9699..2992a41918c2a 100644 --- a/packages/playwright/src/matchers/matchers.ts +++ b/packages/playwright/src/matchers/matchers.ts @@ -14,18 +14,24 @@ * limitations under the License. */ -import type { Locator, Page, APIResponse } from 'playwright-core'; -import type { FrameExpectParams } from 'playwright-core/lib/client/types'; -import { colors } from 'playwright-core/lib/utilsBundle'; -import { expectTypes, callLogText } from '../util'; +import { constructURLBasedOnBaseURL, isRegExp, isString, isTextualMimeType, pollAgainstDeadline, serializeExpectedTextValues } from 'playwright-core/lib/utils'; +import { colors } from 'playwright-core/lib/utils'; + +import { callLogText, expectTypes } from '../util'; import { toBeTruthy } from './toBeTruthy'; import { toEqual } from './toEqual'; +import { toHaveURLWithPredicate } from './toHaveURL'; import { toMatchText } from './toMatchText'; -import { constructURLBasedOnBaseURL, isRegExp, isString, isTextualMimeType, pollAgainstDeadline, serializeExpectedTextValues } from 'playwright-core/lib/utils'; +import { takeFirst } from '../common/config'; import { currentTestInfo } from '../common/globals'; import { TestInfoImpl } from '../worker/testInfo'; + import type { ExpectMatcherState } from '../../types/test'; -import { takeFirst } from '../common/config'; +import type { TestStepInfoImpl } from '../worker/testInfo'; +import type { APIResponse, Locator, Page } from 'playwright-core'; +import type { FrameExpectParams } from 'playwright-core/lib/client/types'; + +export type ExpectMatcherStateInternal = ExpectMatcherState & { _stepInfo?: TestStepInfoImpl }; export interface LocatorEx extends Locator { _expect(expression: string, options: FrameExpectParams): Promise<{ matches: boolean, received?: any, log?: string[], timedOut?: boolean }>; @@ -382,9 +388,13 @@ export function toHaveTitle( export function toHaveURL( this: ExpectMatcherState, page: Page, - expected: string | RegExp, - options?: { ignoreCase?: boolean, timeout?: number }, + expected: string | RegExp | ((url: URL) => boolean), + options?: { ignoreCase?: boolean; timeout?: number }, ) { + // Ports don't support predicates. Keep separate server and client codepaths + if (typeof expected === 'function') + return toHaveURLWithPredicate.call(this, page, expected, options); + const baseURL = (page.context() as any)._options.baseURL; expected = typeof expected === 'string' ? constructURLBasedOnBaseURL(baseURL, expected) : expected; const locator = page.locator(':root') as LocatorEx; diff --git a/packages/playwright/src/matchers/toBeTruthy.ts b/packages/playwright/src/matchers/toBeTruthy.ts index 0075dd5a64454..0faf5555a93b3 100644 --- a/packages/playwright/src/matchers/toBeTruthy.ts +++ b/packages/playwright/src/matchers/toBeTruthy.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -import { expectTypes, callLogText } from '../util'; +import { callLogText, expectTypes } from '../util'; import { kNoElementsFoundError, matcherHint } from './matcherHint'; + import type { MatcherResult } from './matcherHint'; import type { ExpectMatcherState } from '../../types/test'; import type { Locator } from 'playwright-core'; diff --git a/packages/playwright/src/matchers/toEqual.ts b/packages/playwright/src/matchers/toEqual.ts index 4296444a7b4b4..ecbcb1523967d 100644 --- a/packages/playwright/src/matchers/toEqual.ts +++ b/packages/playwright/src/matchers/toEqual.ts @@ -14,12 +14,14 @@ * limitations under the License. */ -import { expectTypes, callLogText } from '../util'; +import { isRegExp } from 'playwright-core/lib/utils'; + +import { callLogText, expectTypes } from '../util'; import { matcherHint } from './matcherHint'; + import type { MatcherResult } from './matcherHint'; import type { ExpectMatcherState } from '../../types/test'; import type { Locator } from 'playwright-core'; -import { isRegExp } from 'playwright-core/lib/utils'; // Omit colon and one or more spaces, so can call getLabelPrinter. const EXPECTED_LABEL = 'Expected'; diff --git a/packages/playwright/src/matchers/toHaveURL.ts b/packages/playwright/src/matchers/toHaveURL.ts new file mode 100644 index 0000000000000..34f05fac33be2 --- /dev/null +++ b/packages/playwright/src/matchers/toHaveURL.ts @@ -0,0 +1,142 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { urlMatches } from 'playwright-core/lib/utils'; +import { colors } from 'playwright-core/lib/utils'; + +import { printReceivedStringContainExpectedResult } from './expect'; +import { matcherHint } from './matcherHint'; +import { EXPECTED_COLOR, printReceived } from '../common/expectBundle'; + +import type { MatcherResult } from './matcherHint'; +import type { ExpectMatcherState } from '../../types/test'; +import type { Page } from 'playwright-core'; + +export async function toHaveURLWithPredicate( + this: ExpectMatcherState, + page: Page, + expected: (url: URL) => boolean, + options?: { ignoreCase?: boolean; timeout?: number }, +): Promise> { + const matcherName = 'toHaveURL'; + const expression = 'page'; + const matcherOptions = { + isNot: this.isNot, + promise: this.promise, + }; + + if (typeof expected !== 'function') { + throw new Error( + [ + // Always display `expected` in expectation place + matcherHint(this, undefined, matcherName, expression, undefined, matcherOptions), + `${colors.bold('Matcher error')}: ${EXPECTED_COLOR('expected')} value must be a string, regular expression, or predicate`, + this.utils.printWithType('Expected', expected, this.utils.printExpected,), + ].join('\n\n'), + ); + } + + const timeout = options?.timeout ?? this.timeout; + const baseURL: string | undefined = (page.context() as any)._options.baseURL; + let conditionSucceeded = false; + let lastCheckedURLString: string | undefined = undefined; + try { + await page.mainFrame().waitForURL( + url => { + lastCheckedURLString = url.toString(); + + if (options?.ignoreCase) { + return ( + !this.isNot === + urlMatches( + baseURL?.toLocaleLowerCase(), + lastCheckedURLString.toLocaleLowerCase(), + expected, + ) + ); + } + + return ( + !this.isNot === urlMatches(baseURL, lastCheckedURLString, expected) + ); + }, + { timeout }, + ); + + conditionSucceeded = true; + } catch (e) { + conditionSucceeded = false; + } + + if (conditionSucceeded) + return { name: matcherName, pass: !this.isNot, message: () => '' }; + + return { + name: matcherName, + pass: this.isNot, + message: () => + toHaveURLMessage( + this, + matcherName, + expression, + expected, + lastCheckedURLString, + this.isNot, + true, + timeout, + ), + actual: lastCheckedURLString, + timeout, + }; +} + +function toHaveURLMessage( + state: ExpectMatcherState, + matcherName: string, + expression: string, + expected: Function, + received: string | undefined, + pass: boolean, + didTimeout: boolean, + timeout: number, +): string { + const matcherOptions = { + isNot: state.isNot, + promise: state.promise, + }; + const receivedString = received || ''; + const messagePrefix = matcherHint(state, undefined, matcherName, expression, undefined, matcherOptions, didTimeout ? timeout : undefined); + + let printedReceived: string | undefined; + let printedExpected: string | undefined; + let printedDiff: string | undefined; + if (typeof expected === 'function') { + printedExpected = `Expected predicate to ${!state.isNot ? 'succeed' : 'fail'}`; + printedReceived = `Received string: ${printReceived(receivedString)}`; + } else { + if (pass) { + printedExpected = `Expected pattern: not ${state.utils.printExpected(expected)}`; + const formattedReceived = printReceivedStringContainExpectedResult(receivedString, null); + printedReceived = `Received string: ${formattedReceived}`; + } else { + const labelExpected = `Expected ${typeof expected === 'string' ? 'string' : 'pattern'}`; + printedDiff = state.utils.printDiffOrStringify(expected, receivedString, labelExpected, 'Received string', false); + } + } + + const resultDetails = printedDiff ? printedDiff : printedExpected + '\n' + printedReceived; + return messagePrefix + resultDetails; +} diff --git a/packages/playwright/src/matchers/toMatchAriaSnapshot.ts b/packages/playwright/src/matchers/toMatchAriaSnapshot.ts index 152ceb6ba90fd..ea38793882d0e 100644 --- a/packages/playwright/src/matchers/toMatchAriaSnapshot.ts +++ b/packages/playwright/src/matchers/toMatchAriaSnapshot.ts @@ -15,27 +15,33 @@ */ -import type { LocatorEx } from './matchers'; -import type { ExpectMatcherState } from '../../types/test'; -import { kNoElementsFoundError, matcherHint, type MatcherResult } from './matcherHint'; +import fs from 'fs'; +import path from 'path'; + +import { escapeTemplateString, isString, sanitizeForFilePath } from 'playwright-core/lib/utils'; + +import { kNoElementsFoundError, matcherHint } from './matcherHint'; import { EXPECTED_COLOR } from '../common/expectBundle'; -import { callLogText, sanitizeFilePathBeforeExtension, trimLongString } from '../util'; +import { callLogText, fileExistsAsync, sanitizeFilePathBeforeExtension, trimLongString } from '../util'; import { printReceivedStringContainExpectedSubstring } from './expect'; import { currentTestInfo } from '../common/globals'; + +import type { MatcherResult } from './matcherHint'; +import type { LocatorEx } from './matchers'; +import type { ExpectMatcherState } from '../../types/test'; import type { MatcherReceived } from '@injected/ariaSnapshot'; -import { escapeTemplateString, isString, sanitizeForFilePath } from 'playwright-core/lib/utils'; -import fs from 'fs'; -import path from 'path'; + type ToMatchAriaSnapshotExpected = { name?: string; path?: string; + timeout?: number; } | string; export async function toMatchAriaSnapshot( this: ExpectMatcherState, receiver: LocatorEx, - expectedParam: ToMatchAriaSnapshotExpected, + expectedParam?: ToMatchAriaSnapshotExpected, options: { timeout?: number } = {}, ): Promise> { const matcherName = 'toMatchAriaSnapshot'; @@ -48,6 +54,8 @@ export async function toMatchAriaSnapshot( return { pass: !this.isNot, message: () => '', name: 'toMatchAriaSnapshot', expected: '' }; const updateSnapshots = testInfo.config.updateSnapshots; + const pathTemplate = testInfo._projectInternal.expect?.toMatchAriaSnapshot?.pathTemplate; + const defaultTemplate = '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{ext}'; const matcherOptions = { isNot: this.isNot, @@ -55,14 +63,15 @@ export async function toMatchAriaSnapshot( }; let expected: string; + let timeout: number; let expectedPath: string | undefined; if (isString(expectedParam)) { expected = expectedParam; + timeout = options.timeout ?? this.timeout; } else { - if (expectedParam?.path) { - expectedPath = expectedParam.path; - } else if (expectedParam?.name) { - expectedPath = testInfo.snapshotPath(sanitizeFilePathBeforeExtension(expectedParam.name)); + if (expectedParam?.name) { + const ext = expectedParam.name!.endsWith('.aria.yml') ? '.aria.yml' : undefined; + expectedPath = testInfo._resolveSnapshotPath(pathTemplate, defaultTemplate, [sanitizeFilePathBeforeExtension(expectedParam.name, ext)]); } else { let snapshotNames = (testInfo as any)[snapshotNamesSymbol] as SnapshotNames; if (!snapshotNames) { @@ -70,9 +79,17 @@ export async function toMatchAriaSnapshot( (testInfo as any)[snapshotNamesSymbol] = snapshotNames; } const fullTitleWithoutSpec = [...testInfo.titlePath.slice(1), ++snapshotNames.anonymousSnapshotIndex].join(' '); - expectedPath = testInfo.snapshotPath(sanitizeForFilePath(trimLongString(fullTitleWithoutSpec)) + '.yml'); + expectedPath = testInfo._resolveSnapshotPath(pathTemplate, defaultTemplate, [sanitizeForFilePath(trimLongString(fullTitleWithoutSpec))], '.aria.yml'); + // in 1.51, we changed the default template to use .aria.yml extension + // for backwards compatibility, we check for the legacy .yml extension + if (!(await fileExistsAsync(expectedPath))) { + const legacyPath = testInfo._resolveSnapshotPath(pathTemplate, defaultTemplate, [sanitizeForFilePath(trimLongString(fullTitleWithoutSpec))], '.yml'); + if (await fileExistsAsync(legacyPath)) + expectedPath = legacyPath; + } } expected = await fs.promises.readFile(expectedPath, 'utf8').catch(() => ''); + timeout = expectedParam?.timeout ?? this.timeout; } const generateMissingBaseline = updateSnapshots === 'missing' && !expected; @@ -86,7 +103,6 @@ export async function toMatchAriaSnapshot( } } - const timeout = options.timeout ?? this.timeout; expected = unshift(expected); const { matches: pass, received, log, timedOut } = await receiver._expect('to.match.aria', { expectedValue: expected, isNot: this.isNot, timeout }); const typedReceived = received as MatcherReceived | typeof kNoElementsFoundError; @@ -136,7 +152,15 @@ export async function toMatchAriaSnapshot( } return { pass: true, message: () => '', name: 'toMatchAriaSnapshot' }; } else { - const suggestedRebaseline = `toMatchAriaSnapshot(\`\n${escapeTemplateString(indent(typedReceived.regex, '{indent} '))}\n{indent}\`)`; + const suggestedRebaseline = `\`\n${escapeTemplateString(indent(typedReceived.regex, '{indent} '))}\n{indent}\``; + if (updateSnapshots === 'missing') { + const message = 'A snapshot is not provided, generating new baseline.'; + testInfo._hasNonRetriableError = true; + testInfo._failWithError(new Error(message)); + } + // TODO: ideally, we should return "pass: true" here because this matcher passes + // when regenerating baselines. However, we can only access suggestedRebaseline in case + // of an error, so we fail here and workaround it in the expect implementation. return { pass: false, message: () => '', name: 'toMatchAriaSnapshot', suggestedRebaseline }; } } diff --git a/packages/playwright/src/matchers/toMatchSnapshot.ts b/packages/playwright/src/matchers/toMatchSnapshot.ts index 8d16f11fc2a78..6cefb48f1eaf7 100644 --- a/packages/playwright/src/matchers/toMatchSnapshot.ts +++ b/packages/playwright/src/matchers/toMatchSnapshot.ts @@ -14,25 +14,29 @@ * limitations under the License. */ -import type { Locator, Page } from 'playwright-core'; -import type { ExpectScreenshotOptions, Page as PageEx } from 'playwright-core/lib/client/page'; -import { currentTestInfo } from '../common/globals'; -import type { ImageComparatorOptions, Comparator } from 'playwright-core/lib/utils'; +import fs from 'fs'; +import path from 'path'; + import { compareBuffersOrStrings, getComparator, isString, sanitizeForFilePath } from 'playwright-core/lib/utils'; +import { colors } from 'playwright-core/lib/utils'; +import { mime } from 'playwright-core/lib/utilsBundle'; + import { - addSuffixToFilePath, - trimLongString, callLogText, + addSuffixToFilePath, callLogText, expectTypes, sanitizeFilePathBeforeExtension, + trimLongString, windowsFilesystemFriendlyLength } from '../util'; -import { colors } from 'playwright-core/lib/utilsBundle'; -import fs from 'fs'; -import path from 'path'; -import { mime } from 'playwright-core/lib/utilsBundle'; -import type { TestInfoImpl } from '../worker/testInfo'; -import type { ExpectMatcherState } from '../../types/test'; -import { matcherHint, type MatcherResult } from './matcherHint'; +import { matcherHint } from './matcherHint'; +import { currentTestInfo } from '../common/globals'; + +import type { MatcherResult } from './matcherHint'; +import type { ExpectMatcherStateInternal } from './matchers'; import type { FullProjectInternal } from '../common/config'; +import type { TestInfoImpl, TestStepInfoImpl } from '../worker/testInfo'; +import type { Locator, Page } from 'playwright-core'; +import type { ExpectScreenshotOptions, Page as PageEx } from 'playwright-core/lib/client/page'; +import type { Comparator, ImageComparatorOptions } from 'playwright-core/lib/utils'; type NameOrSegments = string | string[]; const snapshotNamesSymbol = Symbol('snapshotNames'); @@ -148,7 +152,8 @@ class SnapshotHelper { outputBasePath = testInfo._getOutputPath(sanitizedName); this.attachmentBaseName = sanitizedName; } - this.expectedPath = testInfo.snapshotPath(...expectedPathSegments); + const defaultTemplate = '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{-projectName}{-snapshotSuffix}{ext}'; + this.expectedPath = testInfo._resolveSnapshotPath(configOptions.pathTemplate, defaultTemplate, expectedPathSegments); this.legacyExpectedPath = addSuffixToFilePath(outputBasePath, '-expected'); this.previousPath = addSuffixToFilePath(outputBasePath, '-previous'); this.actualPath = addSuffixToFilePath(outputBasePath, '-actual'); @@ -220,13 +225,13 @@ class SnapshotHelper { return this.createMatcherResult(message, true); } - handleMissing(actual: Buffer | string): ImageMatcherResult { + handleMissing(actual: Buffer | string, step: TestStepInfoImpl | undefined): ImageMatcherResult { const isWriteMissingMode = this.updateSnapshots !== 'none'; if (isWriteMissingMode) writeFileSync(this.expectedPath, actual); - this.testInfo.attachments.push({ name: addSuffixToFilePath(this.attachmentBaseName, '-expected'), contentType: this.mimeType, path: this.expectedPath }); + step?._attachToStep({ name: addSuffixToFilePath(this.attachmentBaseName, '-expected'), contentType: this.mimeType, path: this.expectedPath }); writeFileSync(this.actualPath, actual); - this.testInfo.attachments.push({ name: addSuffixToFilePath(this.attachmentBaseName, '-actual'), contentType: this.mimeType, path: this.actualPath }); + step?._attachToStep({ name: addSuffixToFilePath(this.attachmentBaseName, '-actual'), contentType: this.mimeType, path: this.actualPath }); const message = `A snapshot doesn't exist at ${this.expectedPath}${isWriteMissingMode ? ', writing actual.' : '.'}`; if (this.updateSnapshots === 'all' || this.updateSnapshots === 'changed') { /* eslint-disable no-console */ @@ -248,28 +253,29 @@ class SnapshotHelper { diff: Buffer | string | undefined, header: string, diffError: string, - log: string[] | undefined): ImageMatcherResult { + log: string[] | undefined, + step: TestStepInfoImpl | undefined): ImageMatcherResult { const output = [`${header}${indent(diffError, ' ')}`]; if (expected !== undefined) { // Copy the expectation inside the `test-results/` folder for backwards compatibility, // so that one can upload `test-results/` directory and have all the data inside. writeFileSync(this.legacyExpectedPath, expected); - this.testInfo.attachments.push({ name: addSuffixToFilePath(this.attachmentBaseName, '-expected'), contentType: this.mimeType, path: this.expectedPath }); + step?._attachToStep({ name: addSuffixToFilePath(this.attachmentBaseName, '-expected'), contentType: this.mimeType, path: this.expectedPath }); output.push(`\nExpected: ${colors.yellow(this.expectedPath)}`); } if (previous !== undefined) { writeFileSync(this.previousPath, previous); - this.testInfo.attachments.push({ name: addSuffixToFilePath(this.attachmentBaseName, '-previous'), contentType: this.mimeType, path: this.previousPath }); + step?._attachToStep({ name: addSuffixToFilePath(this.attachmentBaseName, '-previous'), contentType: this.mimeType, path: this.previousPath }); output.push(`Previous: ${colors.yellow(this.previousPath)}`); } if (actual !== undefined) { writeFileSync(this.actualPath, actual); - this.testInfo.attachments.push({ name: addSuffixToFilePath(this.attachmentBaseName, '-actual'), contentType: this.mimeType, path: this.actualPath }); + step?._attachToStep({ name: addSuffixToFilePath(this.attachmentBaseName, '-actual'), contentType: this.mimeType, path: this.actualPath }); output.push(`Received: ${colors.yellow(this.actualPath)}`); } if (diff !== undefined) { writeFileSync(this.diffPath, diff); - this.testInfo.attachments.push({ name: addSuffixToFilePath(this.attachmentBaseName, '-diff'), contentType: this.mimeType, path: this.diffPath }); + step?._attachToStep({ name: addSuffixToFilePath(this.attachmentBaseName, '-diff'), contentType: this.mimeType, path: this.diffPath }); output.push(` Diff: ${colors.yellow(this.diffPath)}`); } @@ -287,7 +293,7 @@ class SnapshotHelper { } export function toMatchSnapshot( - this: ExpectMatcherState, + this: ExpectMatcherStateInternal, received: Buffer | string, nameOrOptions: NameOrSegments | { name?: NameOrSegments } & ImageComparatorOptions = {}, optOptions: ImageComparatorOptions = {} @@ -314,7 +320,7 @@ export function toMatchSnapshot( } if (!fs.existsSync(helper.expectedPath)) - return helper.handleMissing(received); + return helper.handleMissing(received, this._stepInfo); const expected = fs.readFileSync(helper.expectedPath); @@ -343,7 +349,7 @@ export function toMatchSnapshot( const receiver = isString(received) ? 'string' : 'Buffer'; const header = matcherHint(this, undefined, 'toMatchSnapshot', receiver, undefined, undefined); - return helper.handleDifferent(received, expected, undefined, result.diff, header, result.errorMessage, undefined); + return helper.handleDifferent(received, expected, undefined, result.diff, header, result.errorMessage, undefined, this._stepInfo); } export function toHaveScreenshotStepTitle( @@ -359,7 +365,7 @@ export function toHaveScreenshotStepTitle( } export async function toHaveScreenshot( - this: ExpectMatcherState, + this: ExpectMatcherStateInternal, pageOrLocator: Page | Locator, nameOrOptions: NameOrSegments | { name?: NameOrSegments } & ToHaveScreenshotOptions = {}, optOptions: ToHaveScreenshotOptions = {} @@ -424,11 +430,11 @@ export async function toHaveScreenshot( // This can be due to e.g. spinning animation, so we want to show it as a diff. if (errorMessage) { const header = matcherHint(this, locator, 'toHaveScreenshot', receiver, undefined, undefined, timedOut ? timeout : undefined); - return helper.handleDifferent(actual, undefined, previous, diff, header, errorMessage, log); + return helper.handleDifferent(actual, undefined, previous, diff, header, errorMessage, log, this._stepInfo); } // We successfully generated new screenshot. - return helper.handleMissing(actual!); + return helper.handleMissing(actual!, this._stepInfo); } // General case: @@ -459,7 +465,7 @@ export async function toHaveScreenshot( return writeFiles(); const header = matcherHint(this, undefined, 'toHaveScreenshot', receiver, undefined, undefined, timedOut ? timeout : undefined); - return helper.handleDifferent(actual, expectScreenshotOptions.expected, previous, diff, header, errorMessage, log); + return helper.handleDifferent(actual, expectScreenshotOptions.expected, previous, diff, header, errorMessage, log, this._stepInfo); } function writeFileSync(aPath: string, content: Buffer | string) { diff --git a/packages/playwright/src/matchers/toMatchText.ts b/packages/playwright/src/matchers/toMatchText.ts index 2f8bc34b21398..142013f1b58af 100644 --- a/packages/playwright/src/matchers/toMatchText.ts +++ b/packages/playwright/src/matchers/toMatchText.ts @@ -15,17 +15,19 @@ */ -import { expectTypes, callLogText } from '../util'; +import { colors } from 'playwright-core/lib/utils'; + +import { callLogText, expectTypes } from '../util'; import { printReceivedStringContainExpectedResult, printReceivedStringContainExpectedSubstring } from './expect'; -import { EXPECTED_COLOR } from '../common/expectBundle'; -import type { ExpectMatcherState } from '../../types/test'; import { kNoElementsFoundError, matcherHint } from './matcherHint'; +import { EXPECTED_COLOR } from '../common/expectBundle'; + import type { MatcherResult } from './matcherHint'; +import type { ExpectMatcherState } from '../../types/test'; import type { Locator } from 'playwright-core'; -import { colors } from 'playwright-core/lib/utilsBundle'; export async function toMatchText( this: ExpectMatcherState, diff --git a/packages/playwright/src/plugins/gitCommitInfoPlugin.ts b/packages/playwright/src/plugins/gitCommitInfoPlugin.ts index 4c55a3eab33b3..463b6d7aacbea 100644 --- a/packages/playwright/src/plugins/gitCommitInfoPlugin.ts +++ b/packages/playwright/src/plugins/gitCommitInfoPlugin.ts @@ -14,85 +14,162 @@ * limitations under the License. */ -import { createGuid, spawnAsync } from 'playwright-core/lib/utils'; +import * as fs from 'fs'; + +import { spawnAsync } from 'playwright-core/lib/utils'; + import type { TestRunnerPlugin } from './'; import type { FullConfig } from '../../types/testReporter'; +import type { FullConfigInternal } from '../common/config'; +import type { GitCommitInfo, CIInfo, MetadataWithCommitInfo } from '../isomorphic/types'; -const GIT_OPERATIONS_TIMEOUT_MS = 1500; +const GIT_OPERATIONS_TIMEOUT_MS = 3000; + +export const addGitCommitInfoPlugin = (fullConfig: FullConfigInternal) => { + fullConfig.plugins.push({ factory: gitCommitInfoPlugin.bind(null, fullConfig) }); +}; -export const gitCommitInfo = (options?: GitCommitInfoPluginOptions): TestRunnerPlugin => { +const gitCommitInfoPlugin = (fullConfig: FullConfigInternal): TestRunnerPlugin => { return { name: 'playwright:git-commit-info', setup: async (config: FullConfig, configDir: string) => { - const info = { - ...linksFromEnv(), - ...options?.info ? options.info : await gitStatusFromCLI(options?.directory || configDir), - timestamp: Date.now(), - }; - // Normalize dates - const timestamp = info['revision.timestamp']; - if (timestamp instanceof Date) - info['revision.timestamp'] = timestamp.getTime(); - - config.metadata = config.metadata || {}; - Object.assign(config.metadata, info); + const metadata = config.metadata as MetadataWithCommitInfo; + const ci = await ciInfo(); + if (!metadata.ci && ci) + metadata.ci = ci; + + if (fullConfig.captureGitInfo?.commit || (fullConfig.captureGitInfo?.commit === undefined && ci)) { + const git = await gitCommitInfo(configDir).catch(e => { + // eslint-disable-next-line no-console + console.error('Failed to get git commit info', e); + }); + if (git) + metadata.gitCommit = git; + } + + if (fullConfig.captureGitInfo?.diff || (fullConfig.captureGitInfo?.diff === undefined && ci)) { + const diffResult = await gitDiff(configDir, ci).catch(e => { + // eslint-disable-next-line no-console + console.error('Failed to get git diff', e); + }); + if (diffResult) + metadata.gitDiff = diffResult; + } }, }; }; -export interface GitCommitInfoPluginOptions { - directory?: string; - info?: Info; +async function ciInfo(): Promise { + if (process.env.GITHUB_ACTIONS) { + let pr: { title: string, number: number, baseHash: string } | undefined; + try { + const json = JSON.parse(await fs.promises.readFile(process.env.GITHUB_EVENT_PATH!, 'utf8')); + pr = { title: json.pull_request.title, number: json.pull_request.number, baseHash: json.pull_request.base.sha }; + } catch { + } + + return { + commitHref: `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/commit/${process.env.GITHUB_SHA}`, + commitHash: process.env.GITHUB_SHA, + prHref: pr ? `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/pull/${pr.number}` : undefined, + prTitle: pr?.title, + prBaseHash: pr?.baseHash, + buildHref: `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`, + }; + } + + if (process.env.GITLAB_CI) { + return { + commitHref: `${process.env.CI_PROJECT_URL}/-/commit/${process.env.CI_COMMIT_SHA}`, + commitHash: process.env.CI_COMMIT_SHA, + buildHref: process.env.CI_JOB_URL, + branch: process.env.CI_COMMIT_REF_NAME, + }; + } + + if (process.env.JENKINS_URL && process.env.BUILD_URL) { + return { + commitHref: process.env.BUILD_URL, + commitHash: process.env.GIT_COMMIT, + branch: process.env.GIT_BRANCH, + }; + } + + // Open to PRs. } -export interface Info { - 'revision.id'?: string; - 'revision.author'?: string; - 'revision.email'?: string; - 'revision.subject'?: string; - 'revision.timestamp'?: number | Date; - 'revision.link'?: string; - 'ci.link'?: string; +async function gitCommitInfo(gitDir: string): Promise { + const separator = `---786eec917292---`; + const tokens = [ + '%H', // commit hash + '%h', // abbreviated commit hash + '%s', // subject + '%B', // raw body (unwrapped subject and body) + '%an', // author name + '%ae', // author email + '%at', // author date, UNIX timestamp + '%cn', // committer name + '%ce', // committer email + '%ct', // committer date, UNIX timestamp + '', // branch + ]; + const output = await runGit(`git log -1 --pretty=format:"${tokens.join(separator)}" && git rev-parse --abbrev-ref HEAD`, gitDir); + if (!output) + return undefined; + const [hash, shortHash, subject, body, authorName, authorEmail, authorTime, committerName, committerEmail, committerTime, branch] = output.split(separator); + + return { + shortHash, + hash, + subject, + body, + author: { + name: authorName, + email: authorEmail, + time: +authorTime * 1000, + }, + committer: { + name: committerName, + email: committerEmail, + time: +committerTime * 1000, + }, + branch: branch.trim(), + }; } -const linksFromEnv = (): Pick => { - const out: { 'revision.link'?: string; 'ci.link'?: string; } = {}; - // Jenkins: https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables - if (process.env.BUILD_URL) - out['ci.link'] = process.env.BUILD_URL; - // GitLab: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html - if (process.env.CI_PROJECT_URL && process.env.CI_COMMIT_SHA) - out['revision.link'] = `${process.env.CI_PROJECT_URL}/-/commit/${process.env.CI_COMMIT_SHA}`; - if (process.env.CI_JOB_URL) - out['ci.link'] = process.env.CI_JOB_URL; - // GitHub: https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables - if (process.env.GITHUB_SERVER_URL && process.env.GITHUB_REPOSITORY && process.env.GITHUB_SHA) - out['revision.link'] = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/commit/${process.env.GITHUB_SHA}`; - if (process.env.GITHUB_SERVER_URL && process.env.GITHUB_REPOSITORY && process.env.GITHUB_RUN_ID) - out['ci.link'] = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`; - return out; -}; +async function gitDiff(gitDir: string, ci?: CIInfo): Promise { + const diffLimit = 100_000; + if (ci?.prBaseHash) { + await runGit(`git fetch origin ${ci.prBaseHash}`, gitDir); + const diff = await runGit(`git diff ${ci.prBaseHash} HEAD`, gitDir); + if (diff) + return diff.substring(0, diffLimit); + } -export const gitStatusFromCLI = async (gitDir: string): Promise => { - const separator = `:${createGuid().slice(0, 4)}:`; - const { code, stdout } = await spawnAsync( - 'git', - ['show', '-s', `--format=%H${separator}%s${separator}%an${separator}%ae${separator}%ct`, 'HEAD'], - { stdio: 'pipe', cwd: gitDir, timeout: GIT_OPERATIONS_TIMEOUT_MS } - ); - if (code) + // Do not attempt to diff on CI commit. + if (ci) return; - const showOutput = stdout.trim(); - const [id, subject, author, email, rawTimestamp] = showOutput.split(separator); - let timestamp: number = Number.parseInt(rawTimestamp, 10); - timestamp = Number.isInteger(timestamp) ? timestamp * 1000 : 0; - return { - 'revision.id': id, - 'revision.author': author, - 'revision.email': email, - 'revision.subject': subject, - 'revision.timestamp': timestamp, - }; -}; + // Check dirty state first. + const uncommitted = await runGit('git diff', gitDir); + if (uncommitted) + return uncommitted.substring(0, diffLimit); + + // Assume non-shallow checkout on local. + const diff = await runGit('git diff HEAD~1', gitDir); + return diff?.substring(0, diffLimit); +} + +async function runGit(command: string, cwd: string): Promise { + const result = await spawnAsync( + command, + [], + { stdio: 'pipe', cwd, timeout: GIT_OPERATIONS_TIMEOUT_MS, shell: true } + ); + if (process.env.DEBUG_GIT_COMMIT_INFO && result.code) { + // eslint-disable-next-line no-console + console.error(`Failed to run ${command}: ${result.stderr}`); + } + return result.code ? undefined : result.stdout.trim(); +} diff --git a/packages/playwright/src/plugins/index.ts b/packages/playwright/src/plugins/index.ts index 2f7995cb2ffbe..7734145468e25 100644 --- a/packages/playwright/src/plugins/index.ts +++ b/packages/playwright/src/plugins/index.ts @@ -35,4 +35,3 @@ export type TestRunnerPluginRegistration = { }; export { webServer } from './webServerPlugin'; -export { gitCommitInfo } from './gitCommitInfoPlugin'; diff --git a/packages/playwright/src/plugins/webServerPlugin.ts b/packages/playwright/src/plugins/webServerPlugin.ts index 002ad235bd9b5..24d9e4d3fdb13 100644 --- a/packages/playwright/src/plugins/webServerPlugin.ts +++ b/packages/playwright/src/plugins/webServerPlugin.ts @@ -13,14 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import path from 'path'; import net from 'net'; +import path from 'path'; -import { colors, debug } from 'playwright-core/lib/utilsBundle'; -import { raceAgainstDeadline, launchProcess, monotonicTime, isURLAvailable } from 'playwright-core/lib/utils'; +import { launchProcess, isURLAvailable, monotonicTime, raceAgainstDeadline } from 'playwright-core/lib/utils'; +import { colors } from 'playwright-core/lib/utils'; +import { debug } from 'playwright-core/lib/utilsBundle'; -import type { FullConfig } from '../../types/testReporter'; import type { TestRunnerPlugin } from '.'; +import type { FullConfig } from '../../types/testReporter'; import type { FullConfigInternal } from '../common/config'; import type { ReporterV2 } from '../reporters/reporterV2'; diff --git a/packages/playwright/src/program.ts b/packages/playwright/src/program.ts index ea0a48fe6a446..bc899b48c63a6 100644 --- a/packages/playwright/src/program.ts +++ b/packages/playwright/src/program.ts @@ -16,25 +16,29 @@ /* eslint-disable no-console */ -import type { Command } from 'playwright-core/lib/utilsBundle'; import fs from 'fs'; import path from 'path'; -import { Runner } from './runner/runner'; -import { stopProfiling, startProfiling, gracefullyProcessExitDoNotHang } from 'playwright-core/lib/utils'; -import { serializeError } from './util'; -import { showHTMLReport } from './reporters/html'; -import { createMergedReport } from './reporters/merge'; -import { loadConfigFromFileRestartIfNeeded, loadEmptyConfigForMergeReports, resolveConfigLocation } from './common/configLoader'; -import type { ConfigCLIOverrides } from './common/ipc'; -import type { TestError } from '../types/testReporter'; -import type { TraceMode } from '../types/test'; -import { builtInReporters, defaultReporter, defaultTimeout } from './common/config'; + import { program } from 'playwright-core/lib/cli/program'; +import { gracefullyProcessExitDoNotHang, startProfiling, stopProfiling } from 'playwright-core/lib/utils'; + +import { builtInReporters, defaultReporter, defaultTimeout } from './common/config'; +import { loadConfigFromFileRestartIfNeeded, loadEmptyConfigForMergeReports, resolveConfigLocation } from './common/configLoader'; export { program } from 'playwright-core/lib/cli/program'; -import type { ReporterDescription } from '../types/test'; import { prepareErrorStack } from './reporters/base'; +import { showHTMLReport } from './reporters/html'; +import { createMergedReport } from './reporters/merge'; +import { filterProjects } from './runner/projectUtils'; +import { Runner } from './runner/runner'; import * as testServer from './runner/testServer'; import { runWatchModeLoop } from './runner/watchMode'; +import { serializeError } from './util'; + +import type { TestError } from '../types/testReporter'; +import type { ConfigCLIOverrides } from './common/ipc'; +import type { TraceMode } from '../types/test'; +import type { ReporterDescription } from '../types/test'; +import type { Command } from 'playwright-core/lib/utilsBundle'; function addTestCommand(program: Command) { const command = program.command('test [test-filter...]'); @@ -157,6 +161,23 @@ async function runTests(args: string[], opts: { [key: string]: any }) { await startProfiling(); const cliOverrides = overridesFromOptions(opts); + const config = await loadConfigFromFileRestartIfNeeded(opts.config, cliOverrides, opts.deps === false); + if (!config) + return; + + config.cliArgs = args; + config.cliGrep = opts.grep as string | undefined; + config.cliOnlyChanged = opts.onlyChanged === true ? 'HEAD' : opts.onlyChanged; + config.cliGrepInvert = opts.grepInvert as string | undefined; + config.cliListOnly = !!opts.list; + config.cliProjectFilter = opts.project || undefined; + config.cliPassWithNoTests = !!opts.passWithNoTests; + config.cliFailOnFlakyTests = !!opts.failOnFlakyTests; + config.cliLastFailed = !!opts.lastFailed; + + // Evaluate project filters against config before starting execution. This enables a consistent error message across run modes + filterProjects(config.projects, config.cliProjectFilter); + if (opts.ui || opts.uiHost || opts.uiPort) { if (opts.onlyChanged) throw new Error(`--only-changed is not supported in UI mode. If you'd like that to change, see https://github.com/microsoft/playwright/issues/15075 for more details.`); @@ -198,20 +219,6 @@ async function runTests(args: string[], opts: { [key: string]: any }) { return; } - const config = await loadConfigFromFileRestartIfNeeded(opts.config, cliOverrides, opts.deps === false); - if (!config) - return; - - config.cliArgs = args; - config.cliGrep = opts.grep as string | undefined; - config.cliOnlyChanged = opts.onlyChanged === true ? 'HEAD' : opts.onlyChanged; - config.cliGrepInvert = opts.grepInvert as string | undefined; - config.cliListOnly = !!opts.list; - config.cliProjectFilter = opts.project || undefined; - config.cliPassWithNoTests = !!opts.passWithNoTests; - config.cliFailOnFlakyTests = !!opts.failOnFlakyTests; - config.cliLastFailed = !!opts.lastFailed; - const runner = new Runner(config); const status = await runner.runAllTests(); await stopProfiling('runner'); @@ -280,13 +287,11 @@ async function mergeReports(reportDir: string | undefined, opts: { [key: string] } function overridesFromOptions(options: { [key: string]: any }): ConfigCLIOverrides { - const shardPair = options.shard ? options.shard.split('/').map((t: string) => parseInt(t, 10)) : undefined; - - let updateSnapshots: 'all' | 'changed' | 'missing' | 'none'; + let updateSnapshots: 'all' | 'changed' | 'missing' | 'none' | undefined; if (['all', 'changed', 'missing', 'none'].includes(options.updateSnapshots)) updateSnapshots = options.updateSnapshots; else - updateSnapshots = 'updateSnapshots' in options ? 'changed' : 'missing'; + updateSnapshots = 'updateSnapshots' in options ? 'changed' : undefined; const overrides: ConfigCLIOverrides = { forbidOnly: options.forbidOnly ? true : undefined, @@ -298,12 +303,12 @@ function overridesFromOptions(options: { [key: string]: any }): ConfigCLIOverrid repeatEach: options.repeatEach ? parseInt(options.repeatEach, 10) : undefined, retries: options.retries ? parseInt(options.retries, 10) : undefined, reporter: resolveReporterOption(options.reporter), - shard: shardPair ? { current: shardPair[0], total: shardPair[1] } : undefined, + shard: resolveShardOption(options.shard), timeout: options.timeout ? parseInt(options.timeout, 10) : undefined, tsconfig: options.tsconfig ? path.resolve(process.cwd(), options.tsconfig) : undefined, ignoreSnapshots: options.ignoreSnapshots ? !!options.ignoreSnapshots : undefined, updateSnapshots, - updateSourceMethod: options.updateSourceMethod || 'patch', + updateSourceMethod: options.updateSourceMethod, workers: options.workers, }; @@ -332,6 +337,9 @@ function overridesFromOptions(options: { [key: string]: any }): ConfigCLIOverrid overrides.use = overrides.use || {}; overrides.use.trace = options.trace; } + if (overrides.tsconfig && !fs.existsSync(overrides.tsconfig)) + throw new Error(`--tsconfig "${options.tsconfig}" does not exist`); + return overrides; } @@ -341,6 +349,34 @@ function resolveReporterOption(reporter?: string): ReporterDescription[] | undef return reporter.split(',').map((r: string) => [resolveReporter(r)]); } +function resolveShardOption(shard?: string): ConfigCLIOverrides['shard'] { + if (!shard) + return undefined; + + const shardPair = shard.split('/'); + + if (shardPair.length !== 2) { + throw new Error( + `--shard "${shard}", expected format is "current/all", 1-based, for example "3/5".`, + ); + } + + const current = parseInt(shardPair[0], 10); + const total = parseInt(shardPair[1], 10); + + if (isNaN(total) || total < 1) + throw new Error(`--shard "${shard}" total must be a positive number`); + + + if (isNaN(current) || current < 1 || current > total) { + throw new Error( + `--shard "${shard}" current must be a positive number, not greater than shard total`, + ); + } + + return { current, total }; +} + function resolveReporter(id: string) { if (builtInReporters.includes(id as any)) return id; @@ -385,7 +421,7 @@ const testOptions: [string, string][] = [ ['--ui', `Run tests in interactive UI mode`], ['--ui-host ', 'Host to serve UI on; specifying this option opens UI in a browser tab'], ['--ui-port ', 'Port to serve UI on, 0 for any free port; specifying this option opens UI in a browser tab'], - ['-u, --update-snapshots [mode]', `Update snapshots with actual results. Possible values are 'all', 'changed', 'missing' and 'none'. Not passing defaults to 'missing', passing without value defaults to 'changed'`], + ['-u, --update-snapshots [mode]', `Update snapshots with actual results. Possible values are "all", "changed", "missing", and "none". Running tests without the flag defaults to "missing"; running tests with the flag but without a value defaults to "changed".`], ['--update-source-method ', `Chooses the way source is updated. Possible values are 'overwrite', '3way' and 'patch'. Defaults to 'patch'`], ['-j, --workers ', `Number of concurrent workers or percentage of logical CPU cores, use 1 to run in a single worker (default: 50%)`], ['-x', `Stop after the first failure`], diff --git a/packages/playwright/src/prompt.ts b/packages/playwright/src/prompt.ts new file mode 100644 index 0000000000000..141e4a4d5bd3c --- /dev/null +++ b/packages/playwright/src/prompt.ts @@ -0,0 +1,138 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the 'License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as fs from 'fs'; +import * as path from 'path'; + +import { parseErrorStack } from 'playwright-core/lib/utils'; + +import { stripAnsiEscapes } from './util'; +import { codeFrameColumns } from './transform/babelBundle'; + +import type { TestInfo } from '../types/test'; +import type { MetadataWithCommitInfo } from './isomorphic/types'; +import type { TestInfoImpl } from './worker/testInfo'; + +export async function attachErrorPrompts(testInfo: TestInfo, sourceCache: Map, ariaSnapshot: string | undefined) { + if (process.env.PLAYWRIGHT_NO_COPY_PROMPT) + return; + + const meaningfulSingleLineErrors = new Set(testInfo.errors.filter(e => e.message && !e.message.includes('\n')).map(e => e.message!)); + for (const error of testInfo.errors) { + for (const singleLineError of meaningfulSingleLineErrors.keys()) { + if (error.message?.includes(singleLineError)) + meaningfulSingleLineErrors.delete(singleLineError); + } + } + + for (const [index, error] of testInfo.errors.entries()) { + if (!error.message) + return; + if (testInfo.attachments.find(a => a.name === `_prompt-${index}`)) + continue; + + // Skip errors that are just a single line - they are likely to already be the error message. + if (!error.message.includes('\n') && !meaningfulSingleLineErrors.has(error.message)) + continue; + + const metadata = testInfo.config.metadata as MetadataWithCommitInfo; + + const promptParts = [ + `# Instructions`, + '', + `- Following Playwright test failed.`, + `- Explain why, be concise, respect Playwright best practices.`, + `- Provide a snippet of code with the fix, if possible.`, + '', + `# Test info`, + '', + `- Name: ${testInfo.titlePath.slice(1).join(' >> ')}`, + `- Location: ${testInfo.file}:${testInfo.line}:${testInfo.column}`, + '', + '# Error details', + '', + '```', + stripAnsiEscapes(error.stack || error.message || ''), + '```', + ]; + + if (ariaSnapshot) { + promptParts.push( + '', + '# Page snapshot', + '', + '```yaml', + ariaSnapshot, + '```', + ); + } + + const parsedError = error.stack ? parseErrorStack(error.stack, path.sep) : undefined; + const inlineMessage = stripAnsiEscapes(parsedError?.message || error.message || '').split('\n')[0]; + const location = parsedError?.location || { file: testInfo.file, line: testInfo.line, column: testInfo.column }; + const source = await loadSource(location.file, sourceCache); + const codeFrame = codeFrameColumns( + source, + { + start: { + line: location.line, + column: location.column + }, + }, + { + highlightCode: false, + linesAbove: 100, + linesBelow: 100, + message: inlineMessage || undefined, + } + ); + promptParts.push( + '', + '# Test source', + '', + '```ts', + codeFrame, + '```', + ); + + if (metadata.gitDiff) { + promptParts.push( + '', + '# Local changes', + '', + '```diff', + metadata.gitDiff, + '```', + ); + } + + (testInfo as TestInfoImpl)._attach({ + name: `_prompt-${index}`, + contentType: 'text/markdown', + body: Buffer.from(promptParts.join('\n')), + }, undefined); + } +} + +async function loadSource(file: string, sourceCache: Map) { + let source = sourceCache.get(file); + if (!source) { + // A mild race is Ok here. + source = await fs.promises.readFile(file, 'utf8'); + sourceCache.set(file, source); + } + return source; +} diff --git a/packages/playwright/src/reporters/.eslintrc.json b/packages/playwright/src/reporters/.eslintrc.json deleted file mode 100644 index f919272e77920..0000000000000 --- a/packages/playwright/src/reporters/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "no-console": "off" - } -} \ No newline at end of file diff --git a/packages/playwright/src/reporters/base.ts b/packages/playwright/src/reporters/base.ts index ec11413391b8b..30534d7e8f475 100644 --- a/packages/playwright/src/reporters/base.ts +++ b/packages/playwright/src/reporters/base.ts @@ -14,18 +14,22 @@ * limitations under the License. */ -import { colors as realColors, ms as milliseconds, parseStackTraceLine } from 'playwright-core/lib/utilsBundle'; import path from 'path'; -import type { FullConfig, TestCase, Suite, TestResult, TestError, FullResult, TestStep, Location } from '../../types/testReporter'; -import { getPackageManagerExecCommand } from 'playwright-core/lib/utils'; + +import { getPackageManagerExecCommand, parseErrorStack } from 'playwright-core/lib/utils'; +import { ms as milliseconds } from 'playwright-core/lib/utilsBundle'; +import { colors as realColors, noColors } from 'playwright-core/lib/utils'; + +import { ansiRegex, resolveReporterOutputPath, stripAnsiEscapes } from '../util'; import { getEastAsianWidth } from '../utilsBundle'; + import type { ReporterV2 } from './reporterV2'; -import { resolveReporterOutputPath } from '../util'; +import type { FullConfig, FullResult, Location, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; +import type { Colors } from '@isomorphic/colors'; + export type TestResultOutput = { chunk: string | Buffer, type: 'stdout' | 'stderr' }; export const kOutputSymbol = Symbol('output'); -type Colors = typeof realColors; - type ErrorDetails = { message: string; location?: Location; @@ -49,48 +53,6 @@ export type Screen = { ttyWidth: number; }; -export const noColors: Colors = { - bold: (t: string) => t, - cyan: (t: string) => t, - dim: (t: string) => t, - gray: (t: string) => t, - green: (t: string) => t, - red: (t: string) => t, - yellow: (t: string) => t, - black: (t: string) => t, - blue: (t: string) => t, - magenta: (t: string) => t, - white: (t: string) => t, - grey: (t: string) => t, - bgBlack: (t: string) => t, - bgRed: (t: string) => t, - bgGreen: (t: string) => t, - bgYellow: (t: string) => t, - bgBlue: (t: string) => t, - bgMagenta: (t: string) => t, - bgCyan: (t: string) => t, - bgWhite: (t: string) => t, - strip: (t: string) => t, - stripColors: (t: string) => t, - reset: (t: string) => t, - italic: (t: string) => t, - underline: (t: string) => t, - inverse: (t: string) => t, - hidden: (t: string) => t, - strikethrough: (t: string) => t, - rainbow: (t: string) => t, - zebra: (t: string) => t, - america: (t: string) => t, - trap: (t: string) => t, - random: (t: string) => t, - zalgo: (t: string) => t, - - enabled: false, - enable: () => {}, - disable: () => {}, - setTheme: () => {}, -}; - // Output goes to terminal. export const terminalScreen: Screen = (() => { let isTTY = !!process.stdout.isTTY; @@ -307,6 +269,8 @@ export class TerminalReporter implements ReporterV2 { if (full && summary.failuresToPrint.length && !this._omitFailures) this._printFailures(summary.failuresToPrint); this._printSlowTests(); + // TODO: 1.52: Make warning display prettier + // this._printWarnings(); this._printSummary(summaryMessage); } @@ -326,6 +290,28 @@ export class TerminalReporter implements ReporterV2 { console.log(this.screen.colors.yellow(' Consider running tests from slow files in parallel, see https://playwright.dev/docs/test-parallel.')); } + private _printWarnings() { + const warningTests = this.suite.allTests().filter(test => test.annotations.some(a => a.type === 'warning')); + const encounteredWarnings = new Map>(); + for (const test of warningTests) { + for (const annotation of test.annotations) { + if (annotation.type !== 'warning' || annotation.description === undefined) + continue; + let tests = encounteredWarnings.get(annotation.description); + if (!tests) { + tests = []; + encounteredWarnings.set(annotation.description, tests); + } + tests.push(test); + } + } + for (const [description, tests] of encounteredWarnings) { + console.log(this.screen.colors.yellow(' Warning: ') + description); + for (const test of tests) + console.log(this.formatTestHeader(test, { indent: ' ', mode: 'default' })); + } + } + private _printSummary(summary: string) { if (summary.trim()) console.log(summary); @@ -370,6 +356,8 @@ export function formatFailure(screen: Screen, config: FullConfig, test: TestCase resultLines.push(...errors.map(error => '\n' + error.message)); for (let i = 0; i < result.attachments.length; ++i) { const attachment = result.attachments[i]; + if (attachment.name.startsWith('_')) + continue; const hasPrintableContent = attachment.contentType.startsWith('text/'); if (!attachment.path && !hasPrintableContent) continue; @@ -551,28 +539,7 @@ export function prepareErrorStack(stack: string): { stackLines: string[]; location?: Location; } { - const lines = stack.split('\n'); - let firstStackLine = lines.findIndex(line => line.startsWith(' at ')); - if (firstStackLine === -1) - firstStackLine = lines.length; - const message = lines.slice(0, firstStackLine).join('\n'); - const stackLines = lines.slice(firstStackLine); - let location: Location | undefined; - for (const line of stackLines) { - const frame = parseStackTraceLine(line); - if (!frame || !frame.file) - continue; - if (belongsToNodeModules(frame.file)) - continue; - location = { file: frame.file, column: frame.column || 0, line: frame.line || 0 }; - break; - } - return { message, stackLines, location }; -} - -const ansiRegex = new RegExp('([\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~])))', 'g'); -export function stripAnsiEscapes(str: string): string { - return str.replace(ansiRegex, ''); + return parseErrorStack(stack, path.sep, !!process.env.PWDEBUGIMPL); } function characterWidth(c: string) { @@ -627,10 +594,6 @@ export function fitToWidth(line: string, width: number, prefix?: string): string return taken.reverse().join(''); } -function belongsToNodeModules(file: string) { - return file.includes(`${path.sep}node_modules${path.sep}`); -} - function resolveFromEnv(name: string): string | undefined { const value = process.env[name]; if (value) diff --git a/packages/playwright/src/reporters/blob.ts b/packages/playwright/src/reporters/blob.ts index 837fe55be0e9c..4168e1cb68ee2 100644 --- a/packages/playwright/src/reporters/blob.ts +++ b/packages/playwright/src/reporters/blob.ts @@ -16,15 +16,19 @@ import fs from 'fs'; import path from 'path'; -import { ManualPromise, calculateSha1, createGuid, getUserAgent, removeFolders, sanitizeForFilePath } from 'playwright-core/lib/utils'; -import { mime } from 'playwright-core/lib/utilsBundle'; import { Readable } from 'stream'; -import type { EventEmitter } from 'events'; -import type { FullConfig, FullResult, TestResult } from '../../types/testReporter'; -import type { JsonAttachment, JsonEvent } from '../isomorphic/teleReceiver'; -import { TeleReporterEmitter } from './teleEmitter'; + +import { removeFolders, sanitizeForFilePath } from 'playwright-core/lib/utils'; +import { ManualPromise, calculateSha1, createGuid, getUserAgent } from 'playwright-core/lib/utils'; +import { mime } from 'playwright-core/lib/utilsBundle'; import { yazl } from 'playwright-core/lib/zipBundle'; + import { resolveOutputFile } from './base'; +import { TeleReporterEmitter } from './teleEmitter'; + +import type { FullConfig, FullResult, TestResult } from '../../types/testReporter'; +import type { JsonAttachment, JsonEvent } from '../isomorphic/teleReceiver'; +import type { EventEmitter } from 'events'; type BlobReporterOptions = { configDir: string; diff --git a/packages/playwright/src/reporters/dot.ts b/packages/playwright/src/reporters/dot.ts index 7f635f8214377..b3e7b114c0db8 100644 --- a/packages/playwright/src/reporters/dot.ts +++ b/packages/playwright/src/reporters/dot.ts @@ -15,7 +15,8 @@ */ import { TerminalReporter } from './base'; -import type { FullResult, TestCase, TestResult, Suite, TestError } from '../../types/testReporter'; + +import type { FullResult, Suite, TestCase, TestError, TestResult } from '../../types/testReporter'; class DotReporter extends TerminalReporter { private _counter = 0; diff --git a/packages/playwright/src/reporters/github.ts b/packages/playwright/src/reporters/github.ts index e7ec7198fbcc4..826981e862199 100644 --- a/packages/playwright/src/reporters/github.ts +++ b/packages/playwright/src/reporters/github.ts @@ -14,10 +14,15 @@ * limitations under the License. */ -import { ms as milliseconds } from 'playwright-core/lib/utilsBundle'; import path from 'path'; -import { TerminalReporter, formatResultFailure, formatRetry, noColors, stripAnsiEscapes } from './base'; -import type { TestCase, FullResult, TestError } from '../../types/testReporter'; + +import { noColors } from 'playwright-core/lib/utils'; +import { ms as milliseconds } from 'playwright-core/lib/utilsBundle'; + +import { TerminalReporter, formatResultFailure, formatRetry } from './base'; +import { stripAnsiEscapes } from '../util'; + +import type { FullResult, TestCase, TestError } from '../../types/testReporter'; type GitHubLogType = 'debug' | 'notice' | 'warning' | 'error'; diff --git a/packages/playwright/src/reporters/html.ts b/packages/playwright/src/reporters/html.ts index 1fd7695293109..ec83a58046ee0 100644 --- a/packages/playwright/src/reporters/html.ts +++ b/packages/playwright/src/reporters/html.ts @@ -14,23 +14,26 @@ * limitations under the License. */ -import { colors, open } from 'playwright-core/lib/utilsBundle'; -import { MultiMap, getPackageManagerExecCommand } from 'playwright-core/lib/utils'; import fs from 'fs'; import path from 'path'; -import type { TransformCallback } from 'stream'; import { Transform } from 'stream'; + +import { HttpServer, MultiMap, assert, calculateSha1, getPackageManagerExecCommand, copyFileAndMakeWritable, gracefullyProcessExitDoNotHang, removeFolders, sanitizeForFilePath, toPosixPath } from 'playwright-core/lib/utils'; +import { colors } from 'playwright-core/lib/utils'; +import { open } from 'playwright-core/lib/utilsBundle'; +import { mime } from 'playwright-core/lib/utilsBundle'; +import { yazl } from 'playwright-core/lib/zipBundle'; + +import { formatError, formatResultFailure, internalScreen } from './base'; import { codeFrameColumns } from '../transform/babelBundle'; -import type * as api from '../../types/testReporter'; -import { HttpServer, assert, calculateSha1, copyFileAndMakeWritable, gracefullyProcessExitDoNotHang, removeFolders, sanitizeForFilePath, toPosixPath } from 'playwright-core/lib/utils'; -import { formatError, formatResultFailure, internalScreen, stripAnsiEscapes } from './base'; -import { resolveReporterOutputPath } from '../util'; +import { resolveReporterOutputPath, stripAnsiEscapes } from '../util'; + +import type { ReporterV2 } from './reporterV2'; import type { Metadata } from '../../types/test'; -import type { ZipFile } from 'playwright-core/lib/zipBundle'; -import { yazl } from 'playwright-core/lib/zipBundle'; -import { mime } from 'playwright-core/lib/utilsBundle'; +import type * as api from '../../types/testReporter'; import type { HTMLReport, Stats, TestAttachment, TestCase, TestCaseSummary, TestFile, TestFileSummary, TestResult, TestStep } from '@html-reporter/types'; -import type { ReporterV2 } from './reporterV2'; +import type { ZipFile } from 'playwright-core/lib/zipBundle'; +import type { TransformCallback } from 'stream'; type TestEntry = { testCase: TestCase; @@ -517,9 +520,12 @@ class HtmlBuilder { private _createTestStep(dedupedStep: DedupedStep, result: api.TestResult): TestStep { const { step, duration, count } = dedupedStep; - const skipped = dedupedStep.step.category === 'test.step.skip'; + const skipped = dedupedStep.step.annotations?.find(a => a.type === 'skip'); + let title = step.title; + if (skipped) + title = `${title} (skipped${skipped.description ? ': ' + skipped.description : ''})`; const testStep: TestStep = { - title: step.title, + title, startTime: step.startTime.toISOString(), duration, steps: dedupeSteps(step.steps).map(s => this._createTestStep(s, result)), @@ -532,7 +538,7 @@ class HtmlBuilder { location: this._relativeLocation(step.location), error: step.error?.message, count, - skipped + skipped: !!skipped, }; if (step.location) this._stepsInFile.set(step.location.file, testStep); diff --git a/packages/playwright/src/reporters/internalReporter.ts b/packages/playwright/src/reporters/internalReporter.ts index da5e667ffd2c9..85e5d5fb90d97 100644 --- a/packages/playwright/src/reporters/internalReporter.ts +++ b/packages/playwright/src/reporters/internalReporter.ts @@ -15,13 +15,17 @@ */ import fs from 'fs'; -import { codeFrameColumns } from '../transform/babelBundle'; -import type { FullConfig, TestCase, TestError, TestResult, FullResult, TestStep } from '../../types/testReporter'; -import { Suite } from '../common/test'; -import { internalScreen, prepareErrorStack, relativeFilePath } from './base'; -import type { ReporterV2 } from './reporterV2'; + import { monotonicTime } from 'playwright-core/lib/utils'; + +import { internalScreen, prepareErrorStack, relativeFilePath } from './base'; import { Multiplexer } from './multiplexer'; +import { Suite } from '../common/test'; +import { codeFrameColumns } from '../transform/babelBundle'; + +import type { ReporterV2 } from './reporterV2'; +import type { FullConfig, FullResult, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; + export class InternalReporter implements ReporterV2 { private _reporter: ReporterV2; diff --git a/packages/playwright/src/reporters/json.ts b/packages/playwright/src/reporters/json.ts index 3c827aea78f94..ac33d25d9a307 100644 --- a/packages/playwright/src/reporters/json.ts +++ b/packages/playwright/src/reporters/json.ts @@ -16,11 +16,14 @@ import fs from 'fs'; import path from 'path'; -import type { FullConfig, TestCase, Suite, TestResult, TestError, TestStep, FullResult, Location, JSONReport, JSONReportSuite, JSONReportSpec, JSONReportTest, JSONReportTestResult, JSONReportTestStep, JSONReportError } from '../../types/testReporter'; + +import { toPosixPath, MultiMap } from 'playwright-core/lib/utils'; + import { formatError, nonTerminalScreen, prepareErrorStack, resolveOutputFile } from './base'; -import { MultiMap, toPosixPath } from 'playwright-core/lib/utils'; import { getProjectId } from '../common/config'; + import type { ReporterV2 } from './reporterV2'; +import type { FullConfig, FullResult, JSONReport, JSONReportError, JSONReportSpec, JSONReportSuite, JSONReportTest, JSONReportTestResult, JSONReportTestStep, Location, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; type JSONOptions = { outputFile?: string, @@ -200,6 +203,7 @@ class JSONReporter implements ReporterV2 { const steps = result.steps.filter(s => s.category === 'test.step'); const jsonResult: JSONReportTestResult = { workerIndex: result.workerIndex, + parallelIndex: result.parallelIndex, status: result.status, duration: result.duration, error: result.error, diff --git a/packages/playwright/src/reporters/junit.ts b/packages/playwright/src/reporters/junit.ts index 9140fb19d8344..a89ebd7df7fbf 100644 --- a/packages/playwright/src/reporters/junit.ts +++ b/packages/playwright/src/reporters/junit.ts @@ -16,10 +16,14 @@ import fs from 'fs'; import path from 'path'; -import type { FullConfig, FullResult, Suite, TestCase } from '../../types/testReporter'; -import { formatFailure, nonTerminalScreen, resolveOutputFile, stripAnsiEscapes } from './base'; + import { getAsBooleanFromENV } from 'playwright-core/lib/utils'; + +import { formatFailure, nonTerminalScreen, resolveOutputFile } from './base'; +import { stripAnsiEscapes } from '../util'; + import type { ReporterV2 } from './reporterV2'; +import type { FullConfig, FullResult, Suite, TestCase } from '../../types/testReporter'; type JUnitOptions = { outputFile?: string, diff --git a/packages/playwright/src/reporters/line.ts b/packages/playwright/src/reporters/line.ts index 96e393c1cf5f7..b0bf0fd6fdda5 100644 --- a/packages/playwright/src/reporters/line.ts +++ b/packages/playwright/src/reporters/line.ts @@ -15,7 +15,8 @@ */ import { TerminalReporter } from './base'; -import type { TestCase, Suite, TestResult, FullResult, TestStep, TestError } from '../../types/testReporter'; + +import type { FullResult, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; class LineReporter extends TerminalReporter { private _current = 0; @@ -68,12 +69,12 @@ class LineReporter extends TerminalReporter { } onStepBegin(test: TestCase, result: TestResult, step: TestStep) { - if (step.category === 'test.step') + if (this.screen.isTTY && step.category === 'test.step') this._updateLine(test, result, step); } onStepEnd(test: TestCase, result: TestResult, step: TestStep) { - if (step.category === 'test.step') + if (this.screen.isTTY && step.category === 'test.step') this._updateLine(test, result, step.parent); } diff --git a/packages/playwright/src/reporters/list.ts b/packages/playwright/src/reporters/list.ts index 4f885946e52ce..f388f80aef9cf 100644 --- a/packages/playwright/src/reporters/list.ts +++ b/packages/playwright/src/reporters/list.ts @@ -14,10 +14,13 @@ * limitations under the License. */ +import { getAsBooleanFromENV } from 'playwright-core/lib/utils'; import { ms as milliseconds } from 'playwright-core/lib/utilsBundle'; -import { TerminalReporter, stepSuffix, stripAnsiEscapes } from './base'; + +import { TerminalReporter, stepSuffix } from './base'; +import { stripAnsiEscapes } from '../util'; + import type { FullResult, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; -import { getAsBooleanFromENV } from 'playwright-core/lib/utils'; // Allow it in the Visual Studio Code Terminal and the new Windows Terminal const DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === 'win32' && process.env.TERM_PROGRAM !== 'vscode' && !process.env.WT_SESSION; @@ -129,6 +132,8 @@ class ListReporter extends TerminalReporter { if (this._needNewLine) { this._needNewLine = false; process.stdout.write('\n'); + ++this._lastRow; + this._lastColumn = 0; } } @@ -210,6 +215,7 @@ class ListReporter extends TerminalReporter { process.stdout.write('\n'); } ++this._lastRow; + this._lastColumn = 0; } private _updateLine(row: number, text: string, prefix: string) { diff --git a/packages/playwright/src/reporters/markdown.ts b/packages/playwright/src/reporters/markdown.ts index 2b6bcbf063d45..8b2ea93dac1f4 100644 --- a/packages/playwright/src/reporters/markdown.ts +++ b/packages/playwright/src/reporters/markdown.ts @@ -16,10 +16,12 @@ import fs from 'fs'; import path from 'path'; -import type { FullResult, TestCase } from '../../types/testReporter'; + import { resolveReporterOutputPath } from '../util'; import { TerminalReporter } from './base'; +import type { FullResult, TestCase } from '../../types/testReporter'; + type MarkdownReporterOptions = { configDir: string, outputFile?: string; diff --git a/packages/playwright/src/reporters/merge.ts b/packages/playwright/src/reporters/merge.ts index 102335cceb72e..9e2bd2f5df502 100644 --- a/packages/playwright/src/reporters/merge.ts +++ b/packages/playwright/src/reporters/merge.ts @@ -16,17 +16,21 @@ import fs from 'fs'; import path from 'path'; -import type { ReporterDescription } from '../../types/test'; -import type { FullConfigInternal } from '../common/config'; -import type { JsonConfig, JsonEvent, JsonFullResult, JsonLocation, JsonProject, JsonSuite, JsonTestCase, JsonTestResultEnd, JsonTestStepStart, JsonTestStepEnd } from '../isomorphic/teleReceiver'; -import { TeleReporterReceiver } from '../isomorphic/teleReceiver'; + +import { ZipFile } from 'playwright-core/lib/utils'; + +import { currentBlobReportVersion } from './blob'; +import { Multiplexer } from './multiplexer'; import { JsonStringInternalizer, StringInternPool } from '../isomorphic/stringInternPool'; +import { TeleReporterReceiver } from '../isomorphic/teleReceiver'; import { createReporters } from '../runner/reporters'; -import { Multiplexer } from './multiplexer'; -import { ZipFile } from 'playwright-core/lib/utils'; -import { currentBlobReportVersion, type BlobReportMetadata } from './blob'; import { relativeFilePath } from '../util'; + +import type { BlobReportMetadata } from './blob'; +import type { ReporterDescription } from '../../types/test'; import type { TestError } from '../../types/testReporter'; +import type { FullConfigInternal } from '../common/config'; +import type { JsonConfig, JsonEvent, JsonFullResult, JsonLocation, JsonProject, JsonSuite, JsonTestCase, JsonTestResultEnd, JsonTestStepEnd, JsonTestStepStart } from '../isomorphic/teleReceiver'; import type * as blobV1 from './versions/blobV1'; type StatusCallback = (message: string) => void; diff --git a/packages/playwright/src/reporters/multiplexer.ts b/packages/playwright/src/reporters/multiplexer.ts index b666128ab49a0..9ecc9de0f3e4b 100644 --- a/packages/playwright/src/reporters/multiplexer.ts +++ b/packages/playwright/src/reporters/multiplexer.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import type { FullConfig, TestCase, TestError, TestResult, FullResult, TestStep } from '../../types/testReporter'; -import type { Suite } from '../common/test'; import type { ReporterV2 } from './reporterV2'; +import type { FullConfig, FullResult, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; +import type { Suite } from '../common/test'; export class Multiplexer implements ReporterV2 { private _reporters: ReporterV2[]; diff --git a/packages/playwright/src/reporters/reporterV2.ts b/packages/playwright/src/reporters/reporterV2.ts index 2cdffdfe127d1..94cee34213ec8 100644 --- a/packages/playwright/src/reporters/reporterV2.ts +++ b/packages/playwright/src/reporters/reporterV2.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { FullConfig, TestCase, TestError, TestResult, FullResult, TestStep, Reporter, Suite } from '../../types/testReporter'; +import type { FullConfig, FullResult, Reporter, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter'; export interface ReporterV2 { onConfigure?(config: FullConfig): void; diff --git a/packages/playwright/src/reporters/teleEmitter.ts b/packages/playwright/src/reporters/teleEmitter.ts index 0ec92ae9ac12f..7b1571f12bdc5 100644 --- a/packages/playwright/src/reporters/teleEmitter.ts +++ b/packages/playwright/src/reporters/teleEmitter.ts @@ -15,11 +15,14 @@ */ import path from 'path'; + import { createGuid } from 'playwright-core/lib/utils'; -import type * as reporterTypes from '../../types/testReporter'; -import type * as teleReceiver from '../isomorphic/teleReceiver'; + import { serializeRegexPatterns } from '../isomorphic/teleReceiver'; + import type { ReporterV2 } from './reporterV2'; +import type * as reporterTypes from '../../types/testReporter'; +import type * as teleReceiver from '../isomorphic/teleReceiver'; export type TeleReporterEmitterOptions = { omitOutput?: boolean; @@ -181,10 +184,17 @@ export class TeleReporterEmitter implements ReporterV2 { dependencies: project.dependencies, snapshotDir: this._relativePath(project.snapshotDir), teardown: project.teardown, + use: this._serializeProjectUseOptions(project.use), }; return report; } + private _serializeProjectUseOptions(use: reporterTypes.FullProject['use']): Record { + return { + testIdAttribute: use.testIdAttribute, + }; + } + private _serializeSuite(suite: reporterTypes.Suite): teleReceiver.JsonSuite { const result = { title: suite.title, @@ -256,7 +266,8 @@ export class TeleReporterEmitter implements ReporterV2 { id: (step as any)[this._idSymbol], duration: step.duration, error: step.error, - attachments: step.attachments.map(a => result.attachments.indexOf(a)), + attachments: step.attachments.length ? step.attachments.map(a => result.attachments.indexOf(a)) : undefined, + annotations: step.annotations.length ? step.annotations : undefined, }; } diff --git a/packages/playwright/src/runner/dispatcher.ts b/packages/playwright/src/runner/dispatcher.ts index 534fe7eb4a3e2..cf0c7144c0238 100644 --- a/packages/playwright/src/runner/dispatcher.ts +++ b/packages/playwright/src/runner/dispatcher.ts @@ -14,20 +14,24 @@ * limitations under the License. */ -import type { TestBeginPayload, TestEndPayload, DonePayload, TestOutputPayload, StepBeginPayload, StepEndPayload, TeardownErrorsPayload, RunPayload, SerializedConfig, AttachmentPayload } from '../common/ipc'; +import { ManualPromise, eventsHelper } from 'playwright-core/lib/utils'; +import { colors } from 'playwright-core/lib/utils'; + +import { addSuggestedRebaseline } from './rebase'; +import { WorkerHost } from './workerHost'; import { serializeConfig } from '../common/ipc'; -import type { TestResult, TestStep, TestError } from '../../types/testReporter'; -import type { Suite } from '../common/test'; + +import type { FailureTracker } from './failureTracker'; import type { ProcessExitData } from './processHost'; -import type { TestCase } from '../common/test'; -import { ManualPromise, type RegisteredListener, eventsHelper } from 'playwright-core/lib/utils'; -import { WorkerHost } from './workerHost'; import type { TestGroup } from './testGroups'; +import type { TestError, TestResult, TestStep } from '../../types/testReporter'; import type { FullConfigInternal } from '../common/config'; +import type { AttachmentPayload, DonePayload, RunPayload, SerializedConfig, StepBeginPayload, StepEndPayload, TeardownErrorsPayload, TestBeginPayload, TestEndPayload, TestOutputPayload } from '../common/ipc'; +import type { Suite } from '../common/test'; +import type { TestCase } from '../common/test'; import type { ReporterV2 } from '../reporters/reporterV2'; -import type { FailureTracker } from './failureTracker'; -import { colors } from 'playwright-core/lib/utilsBundle'; -import { addSuggestedRebaseline } from './rebase'; +import type { RegisteredListener } from 'playwright-core/lib/utils'; + export type EnvByProjectId = Map>; @@ -321,6 +325,7 @@ class JobDispatcher { duration: -1, steps: [], attachments: [], + annotations: [], location: params.location, }; steps.set(params.stepId, step); @@ -345,6 +350,7 @@ class JobDispatcher { step.error = params.error; if (params.suggestedRebaseline) addSuggestedRebaseline(step.location!, params.suggestedRebaseline); + step.annotations = params.annotations; steps.delete(params.stepId); this._reporter.onStepEnd?.(test, result, step); } diff --git a/packages/playwright/src/runner/lastRun.ts b/packages/playwright/src/runner/lastRun.ts index 2152f977cf071..931bca39726c4 100644 --- a/packages/playwright/src/runner/lastRun.ts +++ b/packages/playwright/src/runner/lastRun.ts @@ -16,8 +16,10 @@ import fs from 'fs'; import path from 'path'; -import type { FullResult, Suite } from '../../types/testReporter'; + import { filterProjects } from './projectUtils'; + +import type { FullResult, Suite } from '../../types/testReporter'; import type { FullConfigInternal } from '../common/config'; import type { ReporterV2 } from '../reporters/reporterV2'; diff --git a/packages/playwright/src/runner/loadUtils.ts b/packages/playwright/src/runner/loadUtils.ts index 62799747b6f69..200f668e5df59 100644 --- a/packages/playwright/src/runner/loadUtils.ts +++ b/packages/playwright/src/runner/loadUtils.ts @@ -15,21 +15,24 @@ */ import path from 'path'; -import type { FullConfig, Reporter, TestError } from '../../types/testReporter'; + import { InProcessLoaderHost, OutOfProcessLoaderHost } from './loaderHost'; -import { Suite } from '../common/test'; -import type { TestCase } from '../common/test'; -import type { FullProjectInternal } from '../common/config'; -import type { FullConfigInternal } from '../common/config'; -import { createFileMatcherFromArguments, createFileFiltersFromArguments, createTitleMatcher, errorWithFile, forceRegExp } from '../util'; -import type { Matcher, TestFileFilter } from '../util'; +import { createFileFiltersFromArguments, createFileMatcherFromArguments, createTitleMatcher, errorWithFile, forceRegExp } from '../util'; import { buildProjectsClosure, collectFilesForProject, filterProjects } from './projectUtils'; -import type { TestRun } from './tasks'; -import { requireOrImport } from '../transform/transform'; +import { createTestGroups, filterForShard } from './testGroups'; import { applyRepeatEachIndex, bindFileSuiteToProject, filterByFocusedLine, filterByTestIds, filterOnly, filterTestsRemoveEmptySuites } from '../common/suiteUtils'; -import { createTestGroups, filterForShard, type TestGroup } from './testGroups'; +import { Suite } from '../common/test'; import { dependenciesForTestFile } from '../transform/compilationCache'; +import { requireOrImport } from '../transform/transform'; import { sourceMapSupport } from '../utilsBundle'; + +import type { TestRun } from './tasks'; +import type { TestGroup } from './testGroups'; +import type { FullConfig, Reporter, TestError } from '../../types/testReporter'; +import type { FullProjectInternal } from '../common/config'; +import type { FullConfigInternal } from '../common/config'; +import type { TestCase } from '../common/test'; +import type { Matcher, TestFileFilter } from '../util'; import type { RawSourceMap } from '../utilsBundle'; diff --git a/packages/playwright/src/runner/loaderHost.ts b/packages/playwright/src/runner/loaderHost.ts index e6db22695ba1e..369cf49a21d70 100644 --- a/packages/playwright/src/runner/loaderHost.ts +++ b/packages/playwright/src/runner/loaderHost.ts @@ -14,15 +14,17 @@ * limitations under the License. */ -import type { TestError } from '../../types/testReporter'; -import { serializeConfig } from '../common/ipc'; import { ProcessHost } from './processHost'; +import { incorporateCompilationCache } from '../common/esmLoaderHost'; +import { serializeConfig } from '../common/ipc'; +import { PoolBuilder } from '../common/poolBuilder'; import { Suite } from '../common/test'; import { loadTestFile } from '../common/testLoader'; -import type { FullConfigInternal } from '../common/config'; -import { PoolBuilder } from '../common/poolBuilder'; import { addToCompilationCache } from '../transform/compilationCache'; -import { incorporateCompilationCache } from '../common/esmLoaderHost'; + +import type { TestError } from '../../types/testReporter'; +import type { FullConfigInternal } from '../common/config'; + export class InProcessLoaderHost { private _config: FullConfigInternal; diff --git a/packages/playwright/src/runner/processHost.ts b/packages/playwright/src/runner/processHost.ts index 4c77c17857a22..cc972b26011bf 100644 --- a/packages/playwright/src/runner/processHost.ts +++ b/packages/playwright/src/runner/processHost.ts @@ -16,12 +16,15 @@ import child_process from 'child_process'; import { EventEmitter } from 'events'; + +import { assert } from 'playwright-core/lib/utils'; import { debug } from 'playwright-core/lib/utilsBundle'; + +import { esmLoaderRegistered } from '../common/esmLoaderHost'; +import { execArgvWithExperimentalLoaderOptions } from '../transform/esmUtils'; + import type { EnvProducedPayload, ProcessInitParams } from '../common/ipc'; import type { ProtocolResponse } from '../common/process'; -import { execArgvWithExperimentalLoaderOptions } from '../transform/esmUtils'; -import { assert } from 'playwright-core/lib/utils'; -import { esmLoaderRegistered } from '../common/esmLoaderHost'; export type ProcessExitData = { unexpectedly: boolean; diff --git a/packages/playwright/src/runner/projectUtils.ts b/packages/playwright/src/runner/projectUtils.ts index 49a6c89d84d2a..b52503c50c495 100644 --- a/packages/playwright/src/runner/projectUtils.ts +++ b/packages/playwright/src/runner/projectUtils.ts @@ -16,12 +16,16 @@ import fs from 'fs'; import path from 'path'; +import { promisify } from 'util'; + import { escapeRegExp } from 'playwright-core/lib/utils'; import { minimatch } from 'playwright-core/lib/utilsBundle'; -import { promisify } from 'util'; -import type { FullProjectInternal } from '../common/config'; + import { createFileMatcher } from '../util'; +import type { FullProjectInternal } from '../common/config'; + + const readFileAsync = promisify(fs.readFile); const readDirAsync = promisify(fs.readdir); diff --git a/packages/playwright/src/runner/rebase.ts b/packages/playwright/src/runner/rebase.ts index de18df465b8a8..79dd3fa998d8f 100644 --- a/packages/playwright/src/runner/rebase.ts +++ b/packages/playwright/src/runner/rebase.ts @@ -14,15 +14,20 @@ * limitations under the License. */ -import path from 'path'; import fs from 'fs'; -import type { T } from '../transform/babelBundle'; -import { types, traverse, babelParse } from '../transform/babelBundle'; +import path from 'path'; + + import { MultiMap } from 'playwright-core/lib/utils'; -import { colors, diff } from 'playwright-core/lib/utilsBundle'; -import type { FullConfigInternal } from '../common/config'; +import { colors } from 'playwright-core/lib/utils'; +import { diff } from 'playwright-core/lib/utilsBundle'; + import { filterProjects } from './projectUtils'; +import { babelParse, traverse, types } from '../transform/babelBundle'; + +import type { FullConfigInternal } from '../common/config'; import type { InternalReporter } from '../reporters/internalReporter'; +import type { T } from '../transform/babelBundle'; const t: typeof T = types; type Location = { @@ -43,6 +48,10 @@ export function addSuggestedRebaseline(location: Location, suggestedRebaseline: suggestedRebaselines.set(location.file, { location, code: suggestedRebaseline }); } +export function clearSuggestedRebaselines() { + suggestedRebaselines.clear(); +} + export async function applySuggestedRebaselines(config: FullConfigInternal, reporter: InternalReporter) { if (config.config.updateSnapshots === 'none') return; @@ -68,24 +77,27 @@ export async function applySuggestedRebaselines(config: FullConfigInternal, repo traverse(fileNode, { CallExpression: path => { const node = path.node; - if (node.arguments.length !== 1) + if (node.arguments.length < 1) return; if (!t.isMemberExpression(node.callee)) return; const argument = node.arguments[0]; if (!t.isStringLiteral(argument) && !t.isTemplateLiteral(argument)) return; - - const matcher = node.callee.property; + const prop = node.callee.property; + if (!prop.loc || !argument.start || !argument.end) + return; + // Replacements are anchored by the location of the call expression. + // However, replacement text is meant to only replace the first argument. for (const replacement of replacements) { // In Babel, rows are 1-based, columns are 0-based. - if (matcher.loc!.start.line !== replacement.location.line) + if (prop.loc.start.line !== replacement.location.line) continue; - if (matcher.loc!.start.column + 1 !== replacement.location.column) + if (prop.loc.start.column + 1 !== replacement.location.column) continue; - const indent = lines[matcher.loc!.start.line - 1].match(/^\s*/)![0]; + const indent = lines[prop.loc.start.line - 1].match(/^\s*/)![0]; const newText = replacement.code.replace(/\{indent\}/g, indent); - ranges.push({ start: matcher.start!, end: node.end!, oldText: source.substring(matcher.start!, node.end!), newText }); + ranges.push({ start: argument.start, end: argument.end, oldText: source.substring(argument.start, argument.end), newText }); // We can have multiple, hopefully equal, replacements for the same location, // for example when a single test runs multiple times because of projects or retries. // Do not apply multiple replacements for the same assertion. diff --git a/packages/playwright/src/runner/reporters.ts b/packages/playwright/src/runner/reporters.ts index b25cb84154e05..6b00a2599c9f1 100644 --- a/packages/playwright/src/runner/reporters.ts +++ b/packages/playwright/src/runner/reporters.ts @@ -15,9 +15,12 @@ */ import path from 'path'; -import type { FullConfig, TestError } from '../../types/testReporter'; + +import { calculateSha1 } from 'playwright-core/lib/utils'; + +import { loadReporter } from './loadUtils'; import { formatError, terminalScreen } from '../reporters/base'; -import type { Screen } from '../reporters/base'; +import { BlobReporter } from '../reporters/blob'; import DotReporter from '../reporters/dot'; import EmptyReporter from '../reporters/empty'; import GitHubReporter from '../reporters/github'; @@ -26,13 +29,15 @@ import JSONReporter from '../reporters/json'; import JUnitReporter from '../reporters/junit'; import LineReporter from '../reporters/line'; import ListReporter from '../reporters/list'; -import type { Suite } from '../common/test'; -import type { BuiltInReporter, FullConfigInternal } from '../common/config'; -import { loadReporter } from './loadUtils'; -import { BlobReporter } from '../reporters/blob'; +import { wrapReporterAsV2 } from '../reporters/reporterV2'; + import type { ReporterDescription } from '../../types/test'; -import { type ReporterV2, wrapReporterAsV2 } from '../reporters/reporterV2'; -import { calculateSha1 } from 'playwright-core/lib/utils'; +import type { FullConfig, TestError } from '../../types/testReporter'; +import type { BuiltInReporter, FullConfigInternal } from '../common/config'; +import type { Suite } from '../common/test'; +import type { Screen } from '../reporters/base'; +import type { ReporterV2 } from '../reporters/reporterV2'; + export async function createReporters(config: FullConfigInternal, mode: 'list' | 'test' | 'merge', isTestServer: boolean, descriptions?: ReporterDescription[]): Promise { const defaultReporters: { [key in BuiltInReporter]: new(arg: any) => ReporterV2 } = { diff --git a/packages/playwright/src/runner/runner.ts b/packages/playwright/src/runner/runner.ts index a1e73657c9307..22694c251e60b 100644 --- a/packages/playwright/src/runner/runner.ts +++ b/packages/playwright/src/runner/runner.ts @@ -15,16 +15,19 @@ * limitations under the License. */ -import type { FullResult, TestError } from '../../types/testReporter'; -import { webServerPluginsForConfig } from '../plugins/webServerPlugin'; +import { LastRunReporter } from './lastRun'; import { collectFilesForProject, filterProjects } from './projectUtils'; import { createErrorCollectingReporter, createReporters } from './reporters'; import { TestRun, createApplyRebaselinesTask, createClearCacheTask, createGlobalSetupTasks, createLoadTask, createPluginSetupTasks, createReportBeginTask, createRunTestsTasks, createStartDevServerTask, runTasks } from './tasks'; -import type { FullConfigInternal } from '../common/config'; -import { affectedTestFiles } from '../transform/compilationCache'; -import { InternalReporter } from '../reporters/internalReporter'; -import { LastRunReporter } from './lastRun'; +import { addGitCommitInfoPlugin } from '../plugins/gitCommitInfoPlugin'; +import { webServerPluginsForConfig } from '../plugins/webServerPlugin'; import { terminalScreen } from '../reporters/base'; +import { InternalReporter } from '../reporters/internalReporter'; +import { affectedTestFiles } from '../transform/compilationCache'; + +import type { FullResult, TestError } from '../../types/testReporter'; +import type { FullConfigInternal } from '../common/config'; + type ProjectConfigWithFiles = { name: string; @@ -70,6 +73,8 @@ export class Runner { const config = this._config; const listOnly = config.cliListOnly; + addGitCommitInfoPlugin(config); + // Legacy webServer support. webServerPluginsForConfig(config).forEach(p => config.plugins.push({ factory: p })); diff --git a/packages/playwright/src/runner/taskRunner.ts b/packages/playwright/src/runner/taskRunner.ts index dd29d6b0f827d..ea0561faaab20 100644 --- a/packages/playwright/src/runner/taskRunner.ts +++ b/packages/playwright/src/runner/taskRunner.ts @@ -14,11 +14,15 @@ * limitations under the License. */ -import { colors, debug } from 'playwright-core/lib/utilsBundle'; import { ManualPromise, monotonicTime } from 'playwright-core/lib/utils'; -import type { FullResult, TestError } from '../../types/testReporter'; +import { colors } from 'playwright-core/lib/utils'; +import { debug } from 'playwright-core/lib/utilsBundle'; + + import { SigIntWatcher } from './sigIntWatcher'; import { serializeError } from '../util'; + +import type { FullResult, TestError } from '../../types/testReporter'; import type { InternalReporter } from '../reporters/internalReporter'; type TaskPhase = (context: Context, errors: TestError[], softErrors: TestError[]) => Promise | void; diff --git a/packages/playwright/src/runner/tasks.ts b/packages/playwright/src/runner/tasks.ts index 84cffac573f60..2bb9c3bbe2281 100644 --- a/packages/playwright/src/runner/tasks.ts +++ b/packages/playwright/src/runner/tasks.ts @@ -17,24 +17,31 @@ import fs from 'fs'; import path from 'path'; import { promisify } from 'util'; + +import { monotonicTime, removeFolders } from 'playwright-core/lib/utils'; import { debug } from 'playwright-core/lib/utilsBundle'; -import { type ManualPromise, monotonicTime, removeFolders } from 'playwright-core/lib/utils'; -import { Dispatcher, type EnvByProjectId } from './dispatcher'; -import type { TestRunnerPluginRegistration } from '../plugins'; -import { createTestGroups, type TestGroup } from '../runner/testGroups'; -import type { Task } from './taskRunner'; -import { TaskRunner } from './taskRunner'; -import type { FullConfigInternal, FullProjectInternal } from '../common/config'; + +import { Dispatcher } from './dispatcher'; +import { FailureTracker } from './failureTracker'; import { collectProjectsAndTestFiles, createRootSuite, loadFileSuites, loadGlobalHook } from './loadUtils'; -import { removeDirAndLogToConsole, type Matcher } from '../util'; -import { Suite } from '../common/test'; import { buildDependentProjects, buildTeardownToSetupsMap, filterProjects } from './projectUtils'; -import { FailureTracker } from './failureTracker'; +import { applySuggestedRebaselines, clearSuggestedRebaselines } from './rebase'; +import { TaskRunner } from './taskRunner'; import { detectChangedTestFiles } from './vcs'; -import type { InternalReporter } from '../reporters/internalReporter'; +import { Suite } from '../common/test'; +import { createTestGroups } from '../runner/testGroups'; import { cacheDir } from '../transform/compilationCache'; +import { removeDirAndLogToConsole } from '../util'; + +import type { TestGroup } from '../runner/testGroups'; +import type { Matcher } from '../util'; +import type { EnvByProjectId } from './dispatcher'; +import type { TestRunnerPluginRegistration } from '../plugins'; +import type { Task } from './taskRunner'; import type { FullResult } from '../../types/testReporter'; -import { applySuggestedRebaselines } from './rebase'; +import type { FullConfigInternal, FullProjectInternal } from '../common/config'; +import type { InternalReporter } from '../reporters/internalReporter'; +import type { ManualPromise } from 'playwright-core/lib/utils'; const readDirAsync = promisify(fs.readdir); @@ -284,6 +291,9 @@ export function createLoadTask(mode: 'out-of-process' | 'in-process', options: { export function createApplyRebaselinesTask(): Task { return { title: 'apply rebaselines', + setup: async () => { + clearSuggestedRebaselines(); + }, teardown: async ({ config, reporter }) => { await applySuggestedRebaselines(config, reporter); }, diff --git a/packages/playwright/src/runner/testServer.ts b/packages/playwright/src/runner/testServer.ts index e3a61329e2a8c..edddbd76ce498 100644 --- a/packages/playwright/src/runner/testServer.ts +++ b/packages/playwright/src/runner/testServer.ts @@ -16,29 +16,33 @@ import fs from 'fs'; import path from 'path'; + import { installRootRedirect, openTraceInBrowser, openTraceViewerApp, registry, startTraceViewerServer } from 'playwright-core/lib/server'; -import { ManualPromise, gracefullyProcessExitDoNotHang, isUnderTest } from 'playwright-core/lib/utils'; -import type { Transport, HttpServer } from 'playwright-core/lib/utils'; -import type * as reporterTypes from '../../types/testReporter'; -import { affectedTestFiles, collectAffectedTestFiles, dependenciesForTestFile } from '../transform/compilationCache'; -import type { ConfigLocation, FullConfigInternal } from '../common/config'; -import { createErrorCollectingReporter, createReporterForTestServer, createReporters } from './reporters'; -import { TestRun, runTasks, createLoadTask, createRunTestsTasks, createReportBeginTask, createListFilesTask, runTasksDeferCleanup, createClearCacheTask, createGlobalSetupTasks, createStartDevServerTask, createApplyRebaselinesTask } from './tasks'; +import { ManualPromise, isUnderTest, gracefullyProcessExitDoNotHang } from 'playwright-core/lib/utils'; import { open } from 'playwright-core/lib/utilsBundle'; -import ListReporter from '../reporters/list'; + +import { createErrorCollectingReporter, createReporterForTestServer, createReporters } from './reporters'; import { SigIntWatcher } from './sigIntWatcher'; -import { Watcher } from '../fsWatcher'; -import type { ReportEntry, TestServerInterface, TestServerInterfaceEventEmitters } from '../isomorphic/testServerInterface'; -import type { ConfigCLIOverrides } from '../common/ipc'; +import { TestRun, createApplyRebaselinesTask, createClearCacheTask, createGlobalSetupTasks, createListFilesTask, createLoadTask, createReportBeginTask, createRunTestsTasks, createStartDevServerTask, runTasks, runTasksDeferCleanup } from './tasks'; import { loadConfig, resolveConfigLocation, restartWithExperimentalTsEsm } from '../common/configLoader'; -import { webServerPluginsForConfig } from '../plugins/webServerPlugin'; -import type { TraceViewerRedirectOptions, TraceViewerServerOptions } from 'playwright-core/lib/server/trace/viewer/traceViewer'; -import type { TestRunnerPluginRegistration } from '../plugins'; -import { serializeError } from '../util'; +import { Watcher } from '../fsWatcher'; import { baseFullConfig } from '../isomorphic/teleReceiver'; +import { addGitCommitInfoPlugin } from '../plugins/gitCommitInfoPlugin'; +import { webServerPluginsForConfig } from '../plugins/webServerPlugin'; +import { internalScreen } from '../reporters/base'; import { InternalReporter } from '../reporters/internalReporter'; +import ListReporter from '../reporters/list'; +import { affectedTestFiles, collectAffectedTestFiles, dependenciesForTestFile } from '../transform/compilationCache'; +import { serializeError } from '../util'; + +import type * as reporterTypes from '../../types/testReporter'; +import type { ConfigLocation, FullConfigInternal } from '../common/config'; +import type { ConfigCLIOverrides } from '../common/ipc'; +import type { ReportEntry, TestServerInterface, TestServerInterfaceEventEmitters } from '../isomorphic/testServerInterface'; +import type { TestRunnerPluginRegistration } from '../plugins'; import type { ReporterV2 } from '../reporters/reporterV2'; -import { internalScreen } from '../reporters/base'; +import type { TraceViewerRedirectOptions, TraceViewerServerOptions } from 'playwright-core/lib/server/trace/viewer/traceViewer'; +import type { HttpServer, Transport } from 'playwright-core/lib/utils'; const originalStdoutWrite = process.stdout.write; const originalStderrWrite = process.stderr.write; @@ -406,6 +410,7 @@ export class TestServerDispatcher implements TestServerInterface { // Preserve plugin instances between setup and build. if (!this._plugins) { webServerPluginsForConfig(config).forEach(p => config.plugins.push({ factory: p })); + addGitCommitInfoPlugin(config); this._plugins = config.plugins || []; } else { config.plugins.splice(0, config.plugins.length, ...this._plugins); diff --git a/packages/playwright/src/runner/vcs.ts b/packages/playwright/src/runner/vcs.ts index da7c4c2cc8e6a..fcda96131821b 100644 --- a/packages/playwright/src/runner/vcs.ts +++ b/packages/playwright/src/runner/vcs.ts @@ -15,9 +15,10 @@ */ import childProcess from 'child_process'; -import { affectedTestFiles } from '../transform/compilationCache'; import path from 'path'; +import { affectedTestFiles } from '../transform/compilationCache'; + export async function detectChangedTestFiles(baseCommit: string, configDir: string): Promise> { function gitFileList(command: string) { try { diff --git a/packages/playwright/src/runner/watchMode.ts b/packages/playwright/src/runner/watchMode.ts index 5c8ddf34a026b..4aa8264312eb8 100644 --- a/packages/playwright/src/runner/watchMode.ts +++ b/packages/playwright/src/runner/watchMode.ts @@ -14,20 +14,25 @@ * limitations under the License. */ -import readline from 'readline'; import path from 'path'; -import { createGuid, eventsHelper, getPackageManagerExecCommand, ManualPromise } from 'playwright-core/lib/utils'; -import type { ConfigLocation } from '../common/config'; -import type { FullResult } from '../../types/testReporter'; -import { colors } from 'playwright-core/lib/utilsBundle'; -import { enquirer } from '../utilsBundle'; -import { separator, terminalScreen } from '../reporters/base'; +import readline from 'readline'; +import { EventEmitter } from 'stream'; + import { PlaywrightServer } from 'playwright-core/lib/remote/playwrightServer'; +import { ManualPromise, createGuid, eventsHelper, getPackageManagerExecCommand } from 'playwright-core/lib/utils'; +import { colors } from 'playwright-core/lib/utils'; + +import { separator, terminalScreen } from '../reporters/base'; +import { enquirer } from '../utilsBundle'; import { TestServerDispatcher } from './testServer'; -import { EventEmitter } from 'stream'; -import { type TestServerTransport, TestServerConnection } from '../isomorphic/testServerConnection'; -import { TeleSuiteUpdater } from '../isomorphic/teleSuiteUpdater'; import { restartWithExperimentalTsEsm } from '../common/configLoader'; +import { TeleSuiteUpdater } from '../isomorphic/teleSuiteUpdater'; +import { TestServerConnection } from '../isomorphic/testServerConnection'; + +import type { FullResult } from '../../types/testReporter'; +import type { ConfigLocation } from '../common/config'; +import type { TestServerTransport } from '../isomorphic/testServerConnection'; + class InMemoryTransport extends EventEmitter implements TestServerTransport { public readonly _send: (data: string) => void; diff --git a/packages/playwright/src/runner/workerHost.ts b/packages/playwright/src/runner/workerHost.ts index 834dd1facfda2..6c6b512574262 100644 --- a/packages/playwright/src/runner/workerHost.ts +++ b/packages/playwright/src/runner/workerHost.ts @@ -16,12 +16,16 @@ import fs from 'fs'; import path from 'path'; -import type { TestGroup } from './testGroups'; -import { stdioChunkToParams } from '../common/ipc'; -import type { RunPayload, SerializedConfig, WorkerInitParams } from '../common/ipc'; + +import { removeFolders } from 'playwright-core/lib/utils'; + import { ProcessHost } from './processHost'; +import { stdioChunkToParams } from '../common/ipc'; import { artifactsFolderName } from '../isomorphic/folders'; -import { removeFolders } from 'playwright-core/lib/utils'; + +import type { TestGroup } from './testGroups'; +import type { RunPayload, SerializedConfig, WorkerInitParams } from '../common/ipc'; + let lastWorkerIndex = 0; diff --git a/packages/playwright/src/third_party/tsconfig-loader.ts b/packages/playwright/src/third_party/tsconfig-loader.ts index b654a3b963925..653e9ab081d79 100644 --- a/packages/playwright/src/third_party/tsconfig-loader.ts +++ b/packages/playwright/src/third_party/tsconfig-loader.ts @@ -24,8 +24,8 @@ /* eslint-disable */ -import * as path from 'path'; -import * as fs from 'fs'; +import path from 'path'; +import fs from 'fs'; import { json5 } from '../utilsBundle'; /** diff --git a/packages/playwright/src/transform/babelBundle.ts b/packages/playwright/src/transform/babelBundle.ts index d2f8b5919ac7c..ce61eecc90a66 100644 --- a/packages/playwright/src/transform/babelBundle.ts +++ b/packages/playwright/src/transform/babelBundle.ts @@ -20,9 +20,9 @@ export const declare: typeof import('../../bundles/babel/node_modules/@types/bab export const types: typeof import('../../bundles/babel/node_modules/@types/babel__core').types = require('./babelBundleImpl').types; export const traverse: typeof import('../../bundles/babel/node_modules/@types/babel__traverse').default = require('./babelBundleImpl').traverse; export type BabelPlugin = [string, any?]; -export type BabelTransformFunction = (code: string, filename: string, isModule: boolean, pluginsPrefix: BabelPlugin[], pluginsSuffix: BabelPlugin[]) => BabelFileResult; +export type BabelTransformFunction = (code: string, filename: string, isModule: boolean, pluginsPrefix: BabelPlugin[], pluginsSuffix: BabelPlugin[]) => BabelFileResult | null; export const babelTransform: BabelTransformFunction = require('./babelBundleImpl').babelTransform; export type BabelParseFunction = (code: string, filename: string, isModule: boolean) => ParseResult; export const babelParse: BabelParseFunction = require('./babelBundleImpl').babelParse; -export type { NodePath, types as T, PluginObj } from '../../bundles/babel/node_modules/@types/babel__core'; +export type { NodePath, PluginObj, types as T } from '../../bundles/babel/node_modules/@types/babel__core'; export type { BabelAPI } from '../../bundles/babel/node_modules/@types/babel__helper-plugin-utils'; diff --git a/packages/playwright/src/transform/compilationCache.ts b/packages/playwright/src/transform/compilationCache.ts index 39c1189ea27d4..87fb7f5654b95 100644 --- a/packages/playwright/src/transform/compilationCache.ts +++ b/packages/playwright/src/transform/compilationCache.ts @@ -17,8 +17,9 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; -import { sourceMapSupport } from '../utilsBundle'; + import { isWorkerProcess } from '../common/globals'; +import { sourceMapSupport } from '../utilsBundle'; export type MemoryCache = { codePath: string; diff --git a/packages/playwright/src/transform/esmLoader.ts b/packages/playwright/src/transform/esmLoader.ts index c84d15146b8fb..6782d7c0a591f 100644 --- a/packages/playwright/src/transform/esmLoader.ts +++ b/packages/playwright/src/transform/esmLoader.ts @@ -16,9 +16,10 @@ import fs from 'fs'; import url from 'url'; + import { addToCompilationCache, currentFileDepsCollector, serializeCompilationCache, startCollectingFileDeps, stopCollectingFileDeps } from './compilationCache'; -import { transformHook, resolveHook, setTransformConfig, shouldTransform, setSingleTSConfig } from './transform'; import { PortTransport } from './portTransport'; +import { resolveHook, setSingleTSConfig, setTransformConfig, shouldTransform, transformHook } from './transform'; import { fileIsModule } from '../util'; // Node < 18.6: defaultResolve takes 3 arguments. @@ -120,4 +121,4 @@ function createTransport(port: MessagePort) { } -module.exports = { resolve, load, globalPreload, initialize }; +module.exports = { globalPreload, initialize, load, resolve }; diff --git a/packages/playwright/src/transform/transform.ts b/packages/playwright/src/transform/transform.ts index 549d83a168cb8..595588d49bcfc 100644 --- a/packages/playwright/src/transform/transform.ts +++ b/packages/playwright/src/transform/transform.ts @@ -16,17 +16,20 @@ import crypto from 'crypto'; import fs from 'fs'; +import Module from 'module'; import path from 'path'; import url from 'url'; -import { sourceMapSupport, pirates } from '../utilsBundle'; -import type { Location } from '../../types/testReporter'; -import type { LoadedTsConfig } from '../third_party/tsconfig-loader'; + import { loadTsConfig } from '../third_party/tsconfig-loader'; -import Module from 'module'; -import type { BabelPlugin, BabelTransformFunction } from './babelBundle'; import { createFileMatcher, fileIsModule, resolveImportSpecifierAfterMapping } from '../util'; +import { pirates, sourceMapSupport } from '../utilsBundle'; +import { belongsToNodeModules, currentFileDepsCollector, getFromCompilationCache, installSourceMapSupport } from './compilationCache'; + +import type { BabelPlugin, BabelTransformFunction } from './babelBundle'; +import type { Location } from '../../types/testReporter'; +import type { LoadedTsConfig } from '../third_party/tsconfig-loader'; import type { Matcher } from '../util'; -import { getFromCompilationCache, currentFileDepsCollector, belongsToNodeModules, installSourceMapSupport } from './compilationCache'; + const version = require('../../package.json').version; @@ -232,9 +235,10 @@ export function transformHook(originalCode: string, filename: string, moduleUrl? const { babelTransform }: { babelTransform: BabelTransformFunction } = require('./babelBundle'); transformData = new Map(); - const { code, map } = babelTransform(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue); - if (!code) - return { code: '', serializedCache }; + const babelResult = babelTransform(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue); + if (!babelResult?.code) + return { code: originalCode, serializedCache }; + const { code, map } = babelResult; const added = addToCache!(code, map, transformData); return { code, serializedCache: added.serializedCache }; } diff --git a/packages/playwright/src/util.ts b/packages/playwright/src/util.ts index f7f91d3198e51..43766be30ea86 100644 --- a/packages/playwright/src/util.ts +++ b/packages/playwright/src/util.ts @@ -15,16 +15,17 @@ */ import fs from 'fs'; -import type { StackFrame } from '@protocol/channels'; -import util from 'util'; import path from 'path'; import url from 'url'; -import { debug, mime, minimatch, parseStackTraceLine } from 'playwright-core/lib/utilsBundle'; -import { formatCallLog } from 'playwright-core/lib/utils'; +import util from 'util'; + +import { parseStackFrame, sanitizeForFilePath, calculateSha1, isRegExp, isString, stringifyStackFrames } from 'playwright-core/lib/utils'; +import { colors, debug, mime, minimatch } from 'playwright-core/lib/utilsBundle'; + import type { Location } from './../types/testReporter'; -import { calculateSha1, isRegExp, isString, sanitizeForFilePath, stringifyStackFrames } from 'playwright-core/lib/utils'; -import type { RawStack } from 'playwright-core/lib/utils'; import type { TestInfoErrorImpl } from './common/ipc'; +import type { StackFrame } from '@protocol/channels'; +import type { RawStack } from 'playwright-core/lib/utils'; const PLAYWRIGHT_TEST_PATH = path.join(__dirname, '..'); const PLAYWRIGHT_CORE_PATH = path.dirname(require.resolve('playwright-core/package.json')); @@ -54,7 +55,7 @@ export function filterStackFile(file: string) { export function filteredStackTrace(rawStack: RawStack): StackFrame[] { const frames: StackFrame[] = []; for (const line of rawStack) { - const frame = parseStackTraceLine(line); + const frame = parseStackFrame(line, path.sep, !!process.env.PWDEBUGIMPL); if (!frame || !frame.file) continue; if (!filterStackFile(frame.file)) @@ -205,8 +206,8 @@ export function addSuffixToFilePath(filePath: string, suffix: string): string { return base + suffix + ext; } -export function sanitizeFilePathBeforeExtension(filePath: string): string { - const ext = path.extname(filePath); +export function sanitizeFilePathBeforeExtension(filePath: string, ext?: string): string { + ext ??= path.extname(filePath); const base = filePath.substring(0, filePath.length - ext.length); return sanitizeForFilePath(base) + ext; } @@ -223,7 +224,14 @@ export function getContainedPath(parentPath: string, subPath: string = ''): stri export const debugTest = debug('pw:test'); -export const callLogText = formatCallLog; +export const callLogText = (log: string[] | undefined) => { + if (!log || !log.some(l => !!l)) + return ''; + return ` +Call log: +${colors.dim(log.join('\n'))} +`; +}; const folderToPackageJsonPath = new Map(); @@ -383,6 +391,15 @@ function fileExists(resolved: string) { return fs.statSync(resolved, { throwIfNoEntry: false })?.isFile(); } +export async function fileExistsAsync(resolved: string) { + try { + const stat = await fs.promises.stat(resolved); + return stat.isFile(); + } catch { + return false; + } +} + function dirExists(resolved: string) { return fs.statSync(resolved, { throwIfNoEntry: false })?.isDirectory(); } @@ -397,3 +414,8 @@ export async function removeDirAndLogToConsole(dir: string) { } catch { } } + +export const ansiRegex = new RegExp('([\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~])))', 'g'); +export function stripAnsiEscapes(str: string): string { + return str.replace(ansiRegex, ''); +} diff --git a/packages/playwright/src/worker/DEPS.list b/packages/playwright/src/worker/DEPS.list index ed3973d1fc4f2..1532b16c9f37a 100644 --- a/packages/playwright/src/worker/DEPS.list +++ b/packages/playwright/src/worker/DEPS.list @@ -4,3 +4,4 @@ ../util.ts ../utilBundle.ts ../matchers/** +../isomorphic/util.ts diff --git a/packages/playwright/src/worker/fixtureRunner.ts b/packages/playwright/src/worker/fixtureRunner.ts index f4fc3736100e2..51bd517ddec2a 100644 --- a/packages/playwright/src/worker/fixtureRunner.ts +++ b/packages/playwright/src/worker/fixtureRunner.ts @@ -14,13 +14,16 @@ * limitations under the License. */ -import { formatLocation, filterStackFile } from '../util'; import { ManualPromise } from 'playwright-core/lib/utils'; + +import { fixtureParameterNames } from '../common/fixtures'; +import { filterStackFile, formatLocation } from '../util'; + import type { TestInfoImpl } from './testInfo'; -import { type FixtureDescription, type RunnableDescription } from './timeoutManager'; -import { fixtureParameterNames, type FixturePool, type FixtureRegistration, type FixtureScope } from '../common/fixtures'; +import type { FixtureDescription, RunnableDescription } from './timeoutManager'; import type { WorkerInfo } from '../../types/test'; import type { Location } from '../../types/testReporter'; +import type { FixturePool, FixtureRegistration, FixtureScope } from '../common/fixtures'; class Fixture { runner: FixtureRunner; @@ -32,7 +35,7 @@ class Fixture { private _selfTeardownComplete: Promise | undefined; private _setupDescription: FixtureDescription; private _teardownDescription: FixtureDescription; - private _stepInfo: { category: 'fixture', location?: Location } | undefined; + private _stepInfo: { title: string, category: 'fixture', location?: Location } | undefined; _deps = new Set(); _usages = new Set(); @@ -44,7 +47,7 @@ class Fixture { const isUserFixture = this.registration.location && filterStackFile(this.registration.location.file); const title = this.registration.customTitle || this.registration.name; const location = isUserFixture ? this.registration.location : undefined; - this._stepInfo = shouldGenerateStep ? { category: 'fixture', location } : undefined; + this._stepInfo = shouldGenerateStep ? { title: `fixture: ${title}`, category: 'fixture', location } : undefined; this._setupDescription = { title, phase: 'setup', @@ -65,13 +68,11 @@ class Fixture { return; } - await testInfo._runAsStage({ - title: `fixture: ${this.registration.customTitle ?? this.registration.name}`, - runnable: { ...runnable, fixture: this._setupDescription }, - stepInfo: this._stepInfo, - }, async () => { - await this._setupInternal(testInfo); - }); + const run = () => testInfo._runWithTimeout({ ...runnable, fixture: this._setupDescription }, () => this._setupInternal(testInfo)); + if (this._stepInfo) + await testInfo._runAsStep(this._stepInfo, run); + else + await run(); } private async _setupInternal(testInfo: TestInfoImpl) { @@ -130,13 +131,11 @@ class Fixture { // Do not even start the teardown for a fixture that does not have any // time remaining in the time slot. This avoids cascading timeouts. if (!testInfo._timeoutManager.isTimeExhaustedFor(fixtureRunnable)) { - await testInfo._runAsStage({ - title: `fixture: ${this.registration.customTitle ?? this.registration.name}`, - runnable: fixtureRunnable, - stepInfo: this._stepInfo, - }, async () => { - await this._teardownInternal(); - }); + const run = () => testInfo._runWithTimeout(fixtureRunnable, () => this._teardownInternal()); + if (this._stepInfo) + await testInfo._runAsStep(this._stepInfo, run); + else + await run(); } } finally { // To preserve fixtures integrity, forcefully cleanup fixtures @@ -265,9 +264,7 @@ export class FixtureRunner { // Do not run the function when fixture setup has already failed. return null; } - await testInfo._runAsStage({ title: 'run function', runnable }, async () => { - await fn(params, testInfo); - }); + await testInfo._runWithTimeout(runnable, () => fn(params, testInfo)); } private async _setupFixtureForRegistration(registration: FixtureRegistration, testInfo: TestInfoImpl, runnable: RunnableDescription): Promise { diff --git a/packages/playwright/src/worker/floatingPromiseScope.ts b/packages/playwright/src/worker/floatingPromiseScope.ts new file mode 100644 index 0000000000000..630183decea50 --- /dev/null +++ b/packages/playwright/src/worker/floatingPromiseScope.ts @@ -0,0 +1,56 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class FloatingPromiseScope { + readonly _floatingCalls: Set> = new Set(); + + /** + * Enables a promise API call to be tracked by the test, alerting if unawaited. + * + * **NOTE:** Returning from an async function wraps the result in a promise, regardless of whether the return value is a promise. This will automatically mark the promise as awaited. Avoid this. + */ + wrapPromiseAPIResult(promise: Promise): Promise { + if (process.env.PW_DISABLE_FLOATING_PROMISES_WARNING) + return promise; + + const promiseProxy = new Proxy(promise, { + get: (target, prop, receiver) => { + if (prop === 'then') { + return (...args: any[]) => { + this._floatingCalls.delete(promise); + + const originalThen = Reflect.get(target, prop, receiver) as Promise['then']; + return originalThen.call(target, ...args); + }; + } else { + return Reflect.get(target, prop, receiver); + } + } + }); + + this._floatingCalls.add(promise); + + return promiseProxy; + } + + clear() { + this._floatingCalls.clear(); + } + + hasFloatingPromises(): boolean { + return this._floatingCalls.size > 0; + } +} diff --git a/packages/playwright/src/worker/testInfo.ts b/packages/playwright/src/worker/testInfo.ts index 3eba79785319d..a5f64e68bf0a2 100644 --- a/packages/playwright/src/worker/testInfo.ts +++ b/packages/playwright/src/worker/testInfo.ts @@ -16,21 +16,27 @@ import fs from 'fs'; import path from 'path'; -import { captureRawStack, monotonicTime, zones, sanitizeForFilePath, stringifyStackFrames } from 'playwright-core/lib/utils'; -import type { TestInfo, TestStatus, FullProject } from '../../types/test'; -import type { AttachmentPayload, StepBeginPayload, StepEndPayload, TestInfoErrorImpl, WorkerInitParams } from '../common/ipc'; -import type { TestCase } from '../common/test'; + +import { captureRawStack, monotonicTime, sanitizeForFilePath, stringifyStackFrames, currentZone } from 'playwright-core/lib/utils'; + import { TimeoutManager, TimeoutManagerError, kMaxDeadline } from './timeoutManager'; +import { filteredStackTrace, getContainedPath, normalizeAndSaveAttachment, trimLongString, windowsFilesystemFriendlyLength } from '../util'; +import { TestTracing } from './testTracing'; +import { testInfoError } from './util'; +import { FloatingPromiseScope } from './floatingPromiseScope'; + import type { RunnableDescription } from './timeoutManager'; -import type { Annotation, FullConfigInternal, FullProjectInternal } from '../common/config'; +import type { FullProject, TestInfo, TestStatus, TestStepInfo } from '../../types/test'; import type { FullConfig, Location } from '../../types/testReporter'; -import { debugTest, filteredStackTrace, formatLocation, getContainedPath, normalizeAndSaveAttachment, trimLongString, windowsFilesystemFriendlyLength } from '../util'; -import { TestTracing } from './testTracing'; +import type { Annotation, FullConfigInternal, FullProjectInternal } from '../common/config'; +import type { AttachmentPayload, StepBeginPayload, StepEndPayload, TestInfoErrorImpl, WorkerInitParams } from '../common/ipc'; +import type { TestCase } from '../common/test'; import type { StackFrame } from '@protocol/channels'; -import { testInfoError } from './util'; + export interface TestStepInternal { complete(result: { error?: Error | unknown, suggestedRebaseline?: string }): void; + info: TestStepInfoImpl attachmentIndices: number[]; stepId: string; title: string; @@ -44,16 +50,8 @@ export interface TestStepInternal { error?: TestInfoErrorImpl; infectParentStepsWithError?: boolean; box?: boolean; - isStage?: boolean; } -export type TestStage = { - title: string; - stepInfo?: { category: 'hook' | 'fixture', location?: Location }; - runnable?: RunnableDescription; - step?: TestStepInternal; -}; - export class TestInfoImpl implements TestInfo { private _onStepBegin: (payload: StepBeginPayload) => void; private _onStepEnd: (payload: StepEndPayload) => void; @@ -62,6 +60,7 @@ export class TestInfoImpl implements TestInfo { readonly _startTime: number; readonly _startWallTime: number; readonly _tracing: TestTracing; + readonly _floatingPromiseScope: FloatingPromiseScope = new FloatingPromiseScope(); _wasInterrupted = false; _lastStepId = 0; @@ -221,35 +220,34 @@ export class TestInfoImpl implements TestInfo { this._timeoutManager.slow(); } else if (type === 'skip' || type === 'fixme') { this.expectedStatus = 'skipped'; - throw new SkipError('Test is skipped: ' + (description || '')); + throw new TestSkipError('Test is skipped: ' + (description || '')); } else if (type === 'fail') { if (this.expectedStatus !== 'skipped') this.expectedStatus = 'failed'; } } - private _findLastStageStep(steps: TestStepInternal[]): TestStepInternal | undefined { - // Find the deepest step that is marked as isStage and has not finished yet. + private _findLastPredefinedStep(steps: TestStepInternal[]): TestStepInternal | undefined { + // Find the deepest predefined step that has not finished yet. for (let i = steps.length - 1; i >= 0; i--) { - const child = this._findLastStageStep(steps[i].steps); + const child = this._findLastPredefinedStep(steps[i].steps); if (child) return child; - if (steps[i].isStage && !steps[i].endWallTime) + if ((steps[i].category === 'hook' || steps[i].category === 'fixture') && !steps[i].endWallTime) return steps[i]; } } private _parentStep() { - return zones.zoneData('stepZone') - ?? this._findLastStageStep(this._steps); // If no parent step on stack, assume the current stage as parent. + return currentZone().data('stepZone') ?? this._findLastPredefinedStep(this._steps); } - _addStep(data: Omit, parentStep?: TestStepInternal): TestStepInternal { + _addStep(data: Omit, parentStep?: TestStepInternal): TestStepInternal { const stepId = `${data.category}@${++this._lastStepId}`; - if (data.isStage) { - // Predefined stages form a fixed hierarchy - use the current one as parent. - parentStep = this._findLastStageStep(this._steps); + if (data.category === 'hook' || data.category === 'fixture') { + // Predefined steps form a fixed hierarchy - use the current one as parent. + parentStep = this._findLastPredefinedStep(this._steps); } else { if (!parentStep) parentStep = this._parentStep(); @@ -269,6 +267,7 @@ export class TestInfoImpl implements TestInfo { ...data, steps: [], attachmentIndices, + info: new TestStepInfoImpl(this, stepId), complete: result => { if (step.endWallTime) return; @@ -302,11 +301,12 @@ export class TestInfoImpl implements TestInfo { wallTime: step.endWallTime, error: step.error, suggestedRebaseline: result.suggestedRebaseline, + annotations: step.info.annotations, }; this._onStepEnd(payload); const errorForTrace = step.error ? { name: '', message: step.error.message || '', stack: step.error.stack } : undefined; const attachments = attachmentIndices.map(i => this.attachments[i]); - this._tracing.appendAfterActionForStep(stepId, errorForTrace, attachments); + this._tracing.appendAfterActionForStep(stepId, errorForTrace, attachments, step.info.annotations); } }; const parentStepList = parentStep ? parentStep.steps : this._steps; @@ -322,7 +322,7 @@ export class TestInfoImpl implements TestInfo { location: data.location, }; this._onStepBegin(payload); - this._tracing.appendBeforeActionForStep(stepId, parentStep?.stepId, data.apiName || data.title, data.params, data.location ? [data.location] : []); + this._tracing.appendBeforeActionForStep(stepId, parentStep?.stepId, data.category, data.apiName || data.title, data.params, data.location ? [data.location] : []); return step; } @@ -346,29 +346,31 @@ export class TestInfoImpl implements TestInfo { this._tracing.appendForError(serialized); } - async _runAsStage(stage: TestStage, cb: () => Promise) { - if (debugTest.enabled) { - const location = stage.runnable?.location ? ` at "${formatLocation(stage.runnable.location)}"` : ``; - debugTest(`started stage "${stage.title}"${location}`); + async _runAsStep(stepInfo: { title: string, category: 'hook' | 'fixture', location?: Location }, cb: () => Promise) { + const step = this._addStep(stepInfo); + try { + await cb(); + step.complete({}); + } catch (error) { + step.complete({ error }); + throw error; } - stage.step = stage.stepInfo ? this._addStep({ ...stage.stepInfo, title: stage.title, isStage: true }) : undefined; + } + async _runWithTimeout(runnable: RunnableDescription, cb: () => Promise) { try { - await this._timeoutManager.withRunnable(stage.runnable, async () => { + await this._timeoutManager.withRunnable(runnable, async () => { try { await cb(); } catch (e) { - // Only handle errors directly thrown by the user code. - if (!stage.runnable) - throw e; - if (this._allowSkips && (e instanceof SkipError)) { + if (this._allowSkips && (e instanceof TestSkipError)) { if (this.status === 'passed') this.status = 'skipped'; } else { // Unfortunately, we have to handle user errors and timeout errors differently. // Consider the following scenario: // - locator.click times out - // - all stages containing the test function finish with TimeoutManagerError + // - all steps containing the test function finish with TimeoutManagerError // - test finishes, the page is closed and this triggers locator.click error // - we would like to present the locator.click error to the user // - therefore, we need a try/catch inside the "run with timeout" block and capture the error @@ -377,16 +379,12 @@ export class TestInfoImpl implements TestInfo { throw e; } }); - stage.step?.complete({}); } catch (error) { // When interrupting, we arrive here with a TimeoutManagerError, but we should not // consider it a timeout. - if (!this._wasInterrupted && (error instanceof TimeoutManagerError) && stage.runnable) + if (!this._wasInterrupted && (error instanceof TimeoutManagerError)) this._failWithError(error); - stage.step?.complete({ error }); throw error; - } finally { - debugTest(`finished stage "${stage.title}"`); } } @@ -414,16 +412,12 @@ export class TestInfoImpl implements TestInfo { step.complete({}); } - private _attach(attachment: TestInfo['attachments'][0], stepId: string | undefined) { + _attach(attachment: TestInfo['attachments'][0], stepId: string | undefined) { const index = this._attachmentsPush(attachment) - 1; - if (stepId) { + if (stepId) this._stepMap.get(stepId)!.attachmentIndices.push(index); - } else { - // trace viewer has no means of representing attachments outside of a step, so we create an artificial action - const callId = `attach@${++this._lastStepId}`; - this._tracing.appendBeforeActionForStep(callId, this._findLastStageStep(this._steps)?.stepId, `attach "${attachment.name}"`, undefined, []); - this._tracing.appendAfterActionForStep(callId, undefined, [attachment]); - } + else + this._tracing.appendTopLevelAttachment(attachment); this._onAttach({ testId: this.testId, @@ -454,14 +448,17 @@ export class TestInfoImpl implements TestInfo { return sanitizeForFilePath(trimLongString(fullTitleWithoutSpec)); } - snapshotPath(...pathSegments: string[]) { + _resolveSnapshotPath(template: string | undefined, defaultTemplate: string, pathSegments: string[], extension?: string) { const subPath = path.join(...pathSegments); - const parsedSubPath = path.parse(subPath); + const dir = path.dirname(subPath); + const ext = extension ?? path.extname(subPath); + const name = path.basename(subPath, ext); const relativeTestFilePath = path.relative(this.project.testDir, this._requireFile); const parsedRelativeTestFilePath = path.parse(relativeTestFilePath); const projectNamePathSegment = sanitizeForFilePath(this.project.name); - const snapshotPath = (this._projectInternal.snapshotPathTemplate || '') + const actualTemplate = (template || this._projectInternal.snapshotPathTemplate || defaultTemplate); + const snapshotPath = actualTemplate .replace(/\{(.)?testDir\}/g, '$1' + this.project.testDir) .replace(/\{(.)?snapshotDir\}/g, '$1' + this.project.snapshotDir) .replace(/\{(.)?snapshotSuffix\}/g, this.snapshotSuffix ? '$1' + this.snapshotSuffix : '') @@ -471,12 +468,17 @@ export class TestInfoImpl implements TestInfo { .replace(/\{(.)?testName\}/g, '$1' + this._fsSanitizedTestName()) .replace(/\{(.)?testFileName\}/g, '$1' + parsedRelativeTestFilePath.base) .replace(/\{(.)?testFilePath\}/g, '$1' + relativeTestFilePath) - .replace(/\{(.)?arg\}/g, '$1' + path.join(parsedSubPath.dir, parsedSubPath.name)) - .replace(/\{(.)?ext\}/g, parsedSubPath.ext ? '$1' + parsedSubPath.ext : ''); + .replace(/\{(.)?arg\}/g, '$1' + path.join(dir, name)) + .replace(/\{(.)?ext\}/g, ext ? '$1' + ext : ''); return path.normalize(path.resolve(this._configInternal.configDir, snapshotPath)); } + snapshotPath(...pathSegments: string[]) { + const legacyTemplate = '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{-projectName}{-snapshotSuffix}{ext}'; + return this._resolveSnapshotPath(undefined, legacyTemplate, pathSegments); + } + skip(...args: [arg?: any, description?: string]) { this._modifier('skip', args); } @@ -498,7 +500,54 @@ export class TestInfoImpl implements TestInfo { } } -export class SkipError extends Error { +export class TestStepInfoImpl implements TestStepInfo { + annotations: Annotation[] = []; + + private _testInfo: TestInfoImpl; + private _stepId: string; + + constructor(testInfo: TestInfoImpl, stepId: string) { + this._testInfo = testInfo; + this._stepId = stepId; + } + + async _runStepBody(skip: boolean, body: (step: TestStepInfo) => T | Promise) { + if (skip) { + this.annotations.push({ type: 'skip' }); + return undefined as T; + } + try { + return await body(this); + } catch (e) { + if (e instanceof StepSkipError) + return undefined as T; + throw e; + } + } + + _attachToStep(attachment: TestInfo['attachments'][0]): void { + this._testInfo._attach(attachment, this._stepId); + } + + async attach(name: string, options?: { body?: string | Buffer; contentType?: string; path?: string; }): Promise { + this._attachToStep(await normalizeAndSaveAttachment(this._testInfo.outputPath(), name, options)); + } + + skip(...args: unknown[]) { + // skip(); + // skip(condition: boolean, description: string); + if (args.length > 0 && !args[0]) + return; + const description = args[1] as (string|undefined); + this.annotations.push({ type: 'skip', description }); + throw new StepSkipError(description); + } +} + +export class TestSkipError extends Error { +} + +export class StepSkipError extends Error { } const stepSymbol = Symbol('step'); diff --git a/packages/playwright/src/worker/testTracing.ts b/packages/playwright/src/worker/testTracing.ts index eb0ce9d80700f..6ef860e1a66db 100644 --- a/packages/playwright/src/worker/testTracing.ts +++ b/packages/playwright/src/worker/testTracing.ts @@ -14,17 +14,21 @@ * limitations under the License. */ -import type { SerializedError, StackFrame } from '@protocol/channels'; -import type * as trace from '@trace/trace'; -import type EventEmitter from 'events'; import fs from 'fs'; import path from 'path'; -import { ManualPromise, calculateSha1, monotonicTime, createGuid, SerializedFS } from 'playwright-core/lib/utils'; + +import { ManualPromise, SerializedFS, calculateSha1, createGuid, monotonicTime } from 'playwright-core/lib/utils'; import { yauzl, yazl } from 'playwright-core/lib/zipBundle'; + +import { kTopLevelAttachmentPrefix } from '../isomorphic/util'; import { filteredStackTrace } from '../util'; -import type { TestInfo, TraceMode, PlaywrightWorkerOptions } from '../../types/test'; + import type { TestInfoImpl } from './testInfo'; +import type { PlaywrightWorkerOptions, TestInfo, TraceMode } from '../../types/test'; import type { TestInfoErrorImpl } from '../common/ipc'; +import type { SerializedError, StackFrame } from '@protocol/channels'; +import type * as trace from '@trace/trace'; +import type EventEmitter from 'events'; export type Attachment = TestInfo['attachments'][0]; export const testTraceEntryName = 'test.trace'; @@ -43,6 +47,8 @@ export class TestTracing { private _artifactsDir: string; private _tracesDir: string; private _contextCreatedEvent: trace.ContextCreatedTraceEvent; + private _didFinishTestFunctionAndAfterEachHooks = false; + private _lastActionId = 0; constructor(testInfo: TestInfoImpl, artifactsDir: string) { this._testInfo = testInfo; @@ -110,6 +116,10 @@ export class TestTracing { } } + didFinishTestFunctionAndAfterEachHooks() { + this._didFinishTestFunctionAndAfterEachHooks = true; + } + artifactsDir() { return this._artifactsDir; } @@ -130,7 +140,7 @@ export class TestTracing { return `${this._testInfo.testId}${retrySuffix}${ordinalSuffix}`; } - generateNextTraceRecordingPath() { + private _generateNextTraceRecordingPath() { const file = path.join(this._artifactsDir, createGuid() + '.zip'); this._temporaryTraceFiles.push(file); return file; @@ -140,6 +150,22 @@ export class TestTracing { return this._options; } + maybeGenerateNextTraceRecordingPath() { + // Forget about traces that should be saved on failure, when no failure happened + // during the test and beforeEach/afterEach hooks. + // This avoids downloading traces over the wire when not really needed. + if (this._didFinishTestFunctionAndAfterEachHooks && this._shouldAbandonTrace()) + return; + return this._generateNextTraceRecordingPath(); + } + + private _shouldAbandonTrace() { + if (!this._options) + return true; + const testFailed = this._testInfo.status !== this._testInfo.expectedStatus; + return !testFailed && (this._options.mode === 'retain-on-failure' || this._options.mode === 'retain-on-first-failure'); + } + async stopIfNeeded() { if (!this._options) return; @@ -148,10 +174,7 @@ export class TestTracing { if (error) throw error; - const testFailed = this._testInfo.status !== this._testInfo.expectedStatus; - const shouldAbandonTrace = !testFailed && (this._options.mode === 'retain-on-failure' || this._options.mode === 'retain-on-first-failure'); - - if (shouldAbandonTrace) { + if (this._shouldAbandonTrace()) { for (const file of this._temporaryTraceFiles) await fs.promises.unlink(file).catch(() => {}); return; @@ -210,7 +233,7 @@ export class TestTracing { await new Promise(f => { zipFile.end(undefined, () => { - zipFile.outputStream.pipe(fs.createWriteStream(this.generateNextTraceRecordingPath())).on('close', f); + zipFile.outputStream.pipe(fs.createWriteStream(this._generateNextTraceRecordingPath())).on('close', f); }); }); @@ -245,7 +268,7 @@ export class TestTracing { }); } - appendBeforeActionForStep(callId: string, parentId: string | undefined, apiName: string, params: Record | undefined, stack: StackFrame[]) { + appendBeforeActionForStep(callId: string, parentId: string | undefined, category: string, apiName: string, params: Record | undefined, stack: StackFrame[]) { this._appendTraceEvent({ type: 'before', callId, @@ -259,16 +282,27 @@ export class TestTracing { }); } - appendAfterActionForStep(callId: string, error?: SerializedError['error'], attachments: Attachment[] = []) { + appendAfterActionForStep(callId: string, error?: SerializedError['error'], attachments: Attachment[] = [], annotations?: trace.AfterActionTraceEventAnnotation[]) { this._appendTraceEvent({ type: 'after', callId, endTime: monotonicTime(), attachments: serializeAttachments(attachments), + annotations, error, }); } + appendTopLevelAttachment(attachment: Attachment) { + // trace viewer has no means of representing attachments outside of a step, + // so we create an artificial action that's hidden in the UI + // the alternative would be to have one hidden step at the end with all top-level attachments, + // but that would delay useful information in live traces. + const callId = `${kTopLevelAttachmentPrefix}@${++this._lastActionId}`; + this.appendBeforeActionForStep(callId, undefined, kTopLevelAttachmentPrefix, `${kTopLevelAttachmentPrefix} "${attachment.name}"`, undefined, []); + this.appendAfterActionForStep(callId, undefined, [attachment]); + } + private _appendTraceEvent(event: trace.TraceEvent) { this._traceEvents.push(event); if (this._liveTraceFile) @@ -277,6 +311,8 @@ export class TestTracing { } function serializeAttachments(attachments: Attachment[]): trace.AfterActionTraceEvent['attachments'] { + if (attachments.length === 0) + return undefined; return attachments.filter(a => a.name !== 'trace').map(a => { return { name: a.name, @@ -335,7 +371,7 @@ async function mergeTraceFiles(fileName: string, temporaryTraceFiles: string[]) // Keep the name for test traces so that the last test trace // that contains most of the information is kept in the trace. // Note the reverse order of the iteration (from new traces to old). - } else if (entry.fileName.match(/[\d-]*trace\./)) { + } else if (entry.fileName.match(/trace\.[a-z]*$/)) { entryName = i + '-' + entry.fileName; } if (entryNames.has(entryName)) { diff --git a/packages/playwright/src/worker/timeoutManager.ts b/packages/playwright/src/worker/timeoutManager.ts index ef7665a6504f0..c003342d15806 100644 --- a/packages/playwright/src/worker/timeoutManager.ts +++ b/packages/playwright/src/worker/timeoutManager.ts @@ -14,8 +14,11 @@ * limitations under the License. */ -import { colors } from 'playwright-core/lib/utilsBundle'; import { ManualPromise, monotonicTime } from 'playwright-core/lib/utils'; +import { colors } from 'playwright-core/lib/utils'; + +import { debugTest, formatLocation } from '../util'; + import type { Location } from '../../types/testReporter'; export type TimeSlot = { @@ -75,9 +78,7 @@ export class TimeoutManager { return slot.timeout > 0 && (slot.elapsed >= slot.timeout - 1); } - async withRunnable(runnable: RunnableDescription | undefined, cb: () => Promise): Promise { - if (!runnable) - return await cb(); + async withRunnable(runnable: RunnableDescription, cb: () => Promise): Promise { if (this._running) throw new Error(`Internal error: duplicate runnable`); const running = this._running = { @@ -88,7 +89,13 @@ export class TimeoutManager { timer: undefined, timeoutPromise: new ManualPromise(), }; + let debugTitle = ''; try { + if (debugTest.enabled) { + debugTitle = runnable.fixture ? `${runnable.fixture.phase} "${runnable.fixture.title}"` : runnable.type; + const location = runnable.location ? ` at "${formatLocation(runnable.location)}"` : ``; + debugTest(`started ${debugTitle}${location}`); + } this._updateTimeout(running); return await Promise.race([ cb(), @@ -100,6 +107,8 @@ export class TimeoutManager { running.timer = undefined; running.slot.elapsed += monotonicTime() - running.start; this._running = undefined; + if (debugTest.enabled) + debugTest(`finished ${debugTitle}`); } } diff --git a/packages/playwright/src/worker/util.ts b/packages/playwright/src/worker/util.ts index a271f62c48ab4..1f8cbc7d488ad 100644 --- a/packages/playwright/src/worker/util.ts +++ b/packages/playwright/src/worker/util.ts @@ -14,10 +14,11 @@ * limitations under the License. */ -import type { TestInfoErrorImpl } from '../common/ipc'; import { ExpectError } from '../matchers/matcherHint'; import { serializeError } from '../util'; +import type { TestInfoErrorImpl } from '../common/ipc'; + export function testInfoError(error: Error | any): TestInfoErrorImpl { const result = serializeError(error); if (error instanceof ExpectError) diff --git a/packages/playwright/src/worker/workerMain.ts b/packages/playwright/src/worker/workerMain.ts index ed323a701bb94..9b61c4b0b0863 100644 --- a/packages/playwright/src/worker/workerMain.ts +++ b/packages/playwright/src/worker/workerMain.ts @@ -14,25 +14,27 @@ * limitations under the License. */ -import { colors } from 'playwright-core/lib/utilsBundle'; -import { debugTest, relativeFilePath } from '../util'; -import type { TestBeginPayload, TestEndPayload, RunPayload, DonePayload, WorkerInitParams, TeardownErrorsPayload, TestInfoErrorImpl } from '../common/ipc'; -import { stdioChunkToParams } from '../common/ipc'; -import { setCurrentTestInfo, setIsWorkerProcess } from '../common/globals'; +import { ManualPromise, gracefullyCloseAll, removeFolders } from 'playwright-core/lib/utils'; +import { colors } from 'playwright-core/lib/utils'; + import { deserializeConfig } from '../common/configLoader'; -import type { Suite, TestCase } from '../common/test'; -import type { Annotation, FullConfigInternal, FullProjectInternal } from '../common/config'; +import { setCurrentTestInfo, setIsWorkerProcess } from '../common/globals'; +import { stdioChunkToParams } from '../common/ipc'; +import { debugTest, relativeFilePath } from '../util'; import { FixtureRunner } from './fixtureRunner'; -import { ManualPromise, gracefullyCloseAll, removeFolders } from 'playwright-core/lib/utils'; -import { SkipError, TestInfoImpl } from './testInfo'; +import { TestSkipError, TestInfoImpl } from './testInfo'; +import { testInfoError } from './util'; +import { inheritFixtureNames } from '../common/fixtures'; +import { PoolBuilder } from '../common/poolBuilder'; import { ProcessRunner } from '../common/process'; -import { loadTestFile } from '../common/testLoader'; import { applyRepeatEachIndex, bindFileSuiteToProject, filterTestsRemoveEmptySuites } from '../common/suiteUtils'; -import { PoolBuilder } from '../common/poolBuilder'; +import { loadTestFile } from '../common/testLoader'; + +import type { TimeSlot } from './timeoutManager'; import type { Location } from '../../types/testReporter'; -import { inheritFixtureNames } from '../common/fixtures'; -import { type TimeSlot } from './timeoutManager'; -import { testInfoError } from './util'; +import type { Annotation, FullConfigInternal, FullProjectInternal } from '../common/config'; +import type { DonePayload, RunPayload, TeardownErrorsPayload, TestBeginPayload, TestEndPayload, TestInfoErrorImpl, WorkerInitParams } from '../common/ipc'; +import type { Suite, TestCase } from '../common/test'; export class WorkerMain extends ProcessRunner { private _params: WorkerInitParams; @@ -75,16 +77,20 @@ export class WorkerMain extends ProcessRunner { process.on('unhandledRejection', reason => this.unhandledError(reason)); process.on('uncaughtException', error => this.unhandledError(error)); - process.stdout.write = (chunk: string | Buffer) => { + process.stdout.write = (chunk: string | Buffer, cb?: any) => { this.dispatchEvent('stdOut', stdioChunkToParams(chunk)); this._currentTest?._tracing.appendStdioToTrace('stdout', chunk); + if (typeof cb === 'function') + process.nextTick(cb); return true; }; if (!process.env.PW_RUNNER_DEBUG) { - process.stderr.write = (chunk: string | Buffer) => { + process.stderr.write = (chunk: string | Buffer, cb?: any) => { this.dispatchEvent('stdErr', stdioChunkToParams(chunk)); this._currentTest?._tracing.appendStdioToTrace('stderr', chunk); + if (typeof cb === 'function') + process.nextTick(cb); return true; }; } @@ -101,16 +107,20 @@ export class WorkerMain extends ProcessRunner { override async gracefullyClose() { try { await this._stop(); + if (!this._config) { + // We never set anything up and we can crash on attempting cleanup + return; + } // Ignore top-level errors, they are already inside TestInfo.errors. const fakeTestInfo = new TestInfoImpl(this._config, this._project, this._params, undefined, 0, () => {}, () => {}, () => {}); const runnable = { type: 'teardown' } as const; // We have to load the project to get the right deadline below. - await fakeTestInfo._runAsStage({ title: 'worker cleanup', runnable }, () => this._loadIfNeeded()).catch(() => {}); + await fakeTestInfo._runWithTimeout(runnable, () => this._loadIfNeeded()).catch(() => {}); await this._fixtureRunner.teardownScope('test', fakeTestInfo, runnable).catch(() => {}); await this._fixtureRunner.teardownScope('worker', fakeTestInfo, runnable).catch(() => {}); // Close any other browsers launched in this process. This includes anything launched // manually in the test/hooks and internal browsers like Playwright Inspector. - await fakeTestInfo._runAsStage({ title: 'worker cleanup', runnable }, () => gracefullyCloseAll()).catch(() => {}); + await fakeTestInfo._runWithTimeout(runnable, () => gracefullyCloseAll()).catch(() => {}); this._fatalErrors.push(...fakeTestInfo.errors); } catch (e) { this._fatalErrors.push(testInfoError(e)); @@ -186,15 +196,19 @@ export class WorkerMain extends ProcessRunner { if (this._config) return; - this._config = await deserializeConfig(this._params.config); - this._project = this._config.projects.find(p => p.id === this._params.projectId)!; + const config = await deserializeConfig(this._params.config); + const project = config.projects.find(p => p.id === this._params.projectId); + if (!project) + throw new Error(`Project "${this._params.projectId}" not found in the worker process. Make sure project name does not change.`); + this._config = config; + this._project = project; this._poolBuilder = PoolBuilder.createForWorker(this._project); } async runTestGroup(runPayload: RunPayload) { this._runFinished = new ManualPromise(); const entries = new Map(runPayload.entries.map(e => [e.testId, e])); - let fatalUnknownTestIds; + let fatalUnknownTestIds: string[] | undefined; try { await this._loadIfNeeded(); const fileSuite = await loadTestFile(runPayload.file, this._config.config.rootDir); @@ -307,8 +321,20 @@ export class WorkerMain extends ProcessRunner { let shouldRunAfterEachHooks = false; testInfo._allowSkips = true; - await testInfo._runAsStage({ title: 'setup and test' }, async () => { - await testInfo._runAsStage({ title: 'start tracing', runnable: { type: 'test' } }, async () => { + + // Create warning if any of the async calls were not awaited in various stages. + const checkForFloatingPromises = (functionDescription: string) => { + if (process.env.PW_DISABLE_FLOATING_PROMISES_WARNING) + return; + if (!testInfo._floatingPromiseScope.hasFloatingPromises()) + return; + // TODO: 1.52: Actually build annotations + // testInfo.annotations.push({ type: 'warning', description: `Some async calls were not awaited by the end of ${functionDescription}. This can cause flakiness.` }); + testInfo._floatingPromiseScope.clear(); + }; + + await (async () => { + await testInfo._runWithTimeout({ type: 'test' }, async () => { // Ideally, "trace" would be an config-level option belonging to the // test runner instead of a fixture belonging to Playwright. // However, for backwards compatibility, we have to read it from a fixture today. @@ -333,7 +359,7 @@ export class WorkerMain extends ProcessRunner { await removeFolders([testInfo.outputDir]); let testFunctionParams: object | null = null; - await testInfo._runAsStage({ title: 'Before Hooks', stepInfo: { category: 'hook' } }, async () => { + await testInfo._runAsStep({ title: 'Before Hooks', category: 'hook' }, async () => { // Run "beforeAll" hooks, unless already run during previous tests. for (const suite of suites) await this._runBeforeAllHooksForSuite(suite, testInfo); @@ -346,17 +372,20 @@ export class WorkerMain extends ProcessRunner { testFunctionParams = await this._fixtureRunner.resolveParametersForFunction(test.fn, testInfo, 'test', { type: 'test' }); }); + checkForFloatingPromises('beforeAll/beforeEach hooks'); + if (testFunctionParams === null) { // Fixture setup failed or was skipped, we should not run the test now. return; } - await testInfo._runAsStage({ title: 'test function', runnable: { type: 'test' } }, async () => { + await testInfo._runWithTimeout({ type: 'test' }, async () => { // Now run the test itself. const fn = test.fn; // Extract a variable to get a better stack trace ("myTest" vs "TestCase.myTest [as fn]"). await fn(testFunctionParams, testInfo); + checkForFloatingPromises('the test'); }); - }).catch(() => {}); // Ignore the top-level error, it is already inside TestInfo.errors. + })().catch(() => {}); // Ignore the top-level error, it is already inside TestInfo.errors. // Update duration, so it is available in fixture teardown and afterEach hooks. testInfo.duration = testInfo._timeoutManager.defaultSlot().elapsed | 0; @@ -367,12 +396,12 @@ export class WorkerMain extends ProcessRunner { // After hooks get an additional timeout. const afterHooksTimeout = calculateMaxTimeout(this._project.project.timeout, testInfo.timeout); const afterHooksSlot = { timeout: afterHooksTimeout, elapsed: 0 }; - await testInfo._runAsStage({ title: 'After Hooks', stepInfo: { category: 'hook' } }, async () => { + await testInfo._runAsStep({ title: 'After Hooks', category: 'hook' }, async () => { let firstAfterHooksError: Error | undefined; try { // Run "immediately upon test function finish" callback. - await testInfo._runAsStage({ title: 'on-test-function-finish', runnable: { type: 'test', slot: afterHooksSlot } }, async () => testInfo._onDidFinishTestFunction?.()); + await testInfo._runWithTimeout({ type: 'test', slot: afterHooksSlot }, async () => testInfo._onDidFinishTestFunction?.()); } catch (error) { firstAfterHooksError = firstAfterHooksError ?? error; } @@ -385,6 +414,8 @@ export class WorkerMain extends ProcessRunner { firstAfterHooksError = firstAfterHooksError ?? error; } + testInfo._tracing.didFinishTestFunctionAndAfterEachHooks(); + try { // Teardown test-scoped fixtures. Attribute to 'test' so that users understand // they should probably increase the test timeout to fix this issue. @@ -410,6 +441,8 @@ export class WorkerMain extends ProcessRunner { throw firstAfterHooksError; }).catch(() => {}); // Ignore the top-level error, it is already inside TestInfo.errors. + checkForFloatingPromises('afterAll/afterEach hooks'); + if (testInfo._isFailure()) this._isStopped = true; @@ -418,7 +451,7 @@ export class WorkerMain extends ProcessRunner { // Mark as "cleaned up" early to avoid running cleanup twice. this._didRunFullCleanup = true; - await testInfo._runAsStage({ title: 'Worker Cleanup', stepInfo: { category: 'hook' } }, async () => { + await testInfo._runAsStep({ title: 'Worker Cleanup', category: 'hook' }, async () => { let firstWorkerCleanupError: Error | undefined; // Give it more time for the full cleanup. @@ -451,7 +484,7 @@ export class WorkerMain extends ProcessRunner { } const tracingSlot = { timeout: this._project.project.timeout, elapsed: 0 }; - await testInfo._runAsStage({ title: 'stop tracing', runnable: { type: 'test', slot: tracingSlot } }, async () => { + await testInfo._runWithTimeout({ type: 'test', slot: tracingSlot }, async () => { await testInfo._tracing.stopIfNeeded(); }).catch(() => {}); // Ignore the top-level error, it is already inside TestInfo.errors. @@ -504,7 +537,7 @@ export class WorkerMain extends ProcessRunner { let firstError: Error | undefined; for (const hook of this._collectHooksAndModifiers(suite, type, testInfo)) { try { - await testInfo._runAsStage({ title: hook.title, stepInfo: { category: 'hook', location: hook.location } }, async () => { + await testInfo._runAsStep({ title: hook.title, category: 'hook', location: hook.location }, async () => { // Separate time slot for each beforeAll/afterAll hook. const timeSlot = { timeout: this._project.project.timeout, elapsed: 0 }; const runnable = { type: hook.type, slot: timeSlot, location: hook.location }; @@ -525,7 +558,7 @@ export class WorkerMain extends ProcessRunner { } catch (error) { firstError = firstError ?? error; // Skip in beforeAll/modifier prevents others from running. - if (type === 'beforeAll' && (error instanceof SkipError)) + if (type === 'beforeAll' && (error instanceof TestSkipError)) break; if (type === 'beforeAll' && !this._skipRemainingTestsInSuite) { // This will inform dispatcher that we should not run more tests from this group @@ -557,13 +590,13 @@ export class WorkerMain extends ProcessRunner { continue; } try { - await testInfo._runAsStage({ title: hook.title, stepInfo: { category: 'hook', location: hook.location } }, async () => { + await testInfo._runAsStep({ title: hook.title, category: 'hook', location: hook.location }, async () => { await this._fixtureRunner.resolveParametersAndRunFunction(hook.fn, testInfo, 'test', runnable); }); } catch (error) { firstError = firstError ?? error; // Skip in modifier prevents others from running. - if (error instanceof SkipError) + if (error instanceof TestSkipError) break; } } diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index e01271ceec475..1d95350d0d9d6 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -214,6 +214,27 @@ interface TestProject { * [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). */ stylePath?: string|Array; + + /** + * A template controlling location of the screenshots. See + * [testProject.snapshotPathTemplate](https://playwright.dev/docs/api/class-testproject#test-project-snapshot-path-template) + * for details. + */ + pathTemplate?: string; + }; + + /** + * Configuration for the + * [expect(locator).toMatchAriaSnapshot([options])](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-match-aria-snapshot-2) + * method. + */ + toMatchAriaSnapshot?: { + /** + * A template controlling location of the aria snapshots. See + * [testProject.snapshotPathTemplate](https://playwright.dev/docs/api/class-testproject#test-project-snapshot-path-template) + * for details. + */ + pathTemplate?: string; }; /** @@ -328,6 +349,10 @@ interface TestProject { /** * Project name is visible in the report and during test execution. + * + * **NOTE** Playwright executes the configuration file multiple times. Do not dynamically produce non-stable values in + * your configuration. + * */ name?: string; @@ -404,10 +429,14 @@ interface TestProject { /** * This option configures a template controlling location of snapshots generated by - * [expect(page).toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * [expect(page).toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1), + * [expect(locator).toMatchAriaSnapshot([options])](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-match-aria-snapshot-2) * and * [expect(value).toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1). * + * You can configure templates for each assertion separately in + * [testConfig.expect](https://playwright.dev/docs/api/class-testconfig#test-config-expect). + * * **Usage** * * ```js @@ -416,7 +445,19 @@ interface TestProject { * * export default defineConfig({ * testDir: './tests', + * + * // Single template for all assertions * snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}', + * + * // Assertion-specific templates + * expect: { + * toHaveScreenshot: { + * pathTemplate: '{testDir}/__screenshots__{/projectName}/{testFilePath}/{arg}{ext}', + * }, + * toMatchAriaSnapshot: { + * pathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}', + * }, + * }, * }); * ``` * @@ -447,27 +488,27 @@ interface TestProject { * ``` * * The list of supported tokens: - * - `{arg}` - Relative snapshot path **without extension**. These come from the arguments passed to the - * `toHaveScreenshot()` and `toMatchSnapshot()` calls; if called without arguments, this will be an auto-generated - * snapshot name. + * - `{arg}` - Relative snapshot path **without extension**. This comes from the arguments passed to + * `toHaveScreenshot()`, `toMatchAriaSnapshot()` or `toMatchSnapshot()`; if called without arguments, this will be + * an auto-generated snapshot name. * - Value: `foo/bar/baz` - * - `{ext}` - snapshot extension (with dots) + * - `{ext}` - Snapshot extension (with the leading dot). * - Value: `.png` * - `{platform}` - The value of `process.platform`. * - `{projectName}` - Project's file-system-sanitized name, if any. * - Value: `''` (empty string). * - `{snapshotDir}` - Project's - * [testConfig.snapshotDir](https://playwright.dev/docs/api/class-testconfig#test-config-snapshot-dir). + * [testProject.snapshotDir](https://playwright.dev/docs/api/class-testproject#test-project-snapshot-dir). * - Value: `/home/playwright/tests` (since `snapshotDir` is not provided in config, it defaults to `testDir`) * - `{testDir}` - Project's - * [testConfig.testDir](https://playwright.dev/docs/api/class-testconfig#test-config-test-dir). - * - Value: `/home/playwright/tests` (absolute path is since `testDir` is resolved relative to directory with + * [testProject.testDir](https://playwright.dev/docs/api/class-testproject#test-project-test-dir). + * - Value: `/home/playwright/tests` (absolute path since `testDir` is resolved relative to directory with * config) * - `{testFileDir}` - Directories in relative path from `testDir` to **test file**. * - Value: `page` * - `{testFileName}` - Test file name with extension. * - Value: `page-click.spec.ts` - * - `{testFilePath}` - Relative path from `testDir` to **test file** + * - `{testFilePath}` - Relative path from `testDir` to **test file**. * - Value: `page/page-click.spec.ts` * - `{testName}` - File-system-sanitized test title, including parent describes but excluding file name. * - Value: `suite-test-should-work` @@ -843,7 +884,7 @@ interface TestConfig { * export default defineConfig({ * webServer: { * command: 'npm run start', - * url: 'http://127.0.0.1:3000', + * url: 'http://localhost:3000', * timeout: 120 * 1000, * reuseExistingServer: !process.env.CI, * }, @@ -874,19 +915,19 @@ interface TestConfig { * webServer: [ * { * command: 'npm run start', - * url: 'http://127.0.0.1:3000', + * url: 'http://localhost:3000', * timeout: 120 * 1000, * reuseExistingServer: !process.env.CI, * }, * { * command: 'npm run backend', - * url: 'http://127.0.0.1:3333', + * url: 'http://localhost:3333', * timeout: 120 * 1000, * reuseExistingServer: !process.env.CI, * } * ], * use: { - * baseURL: 'http://127.0.0.1:3000', + * baseURL: 'http://localhost:3000', * }, * }); * ``` @@ -918,6 +959,44 @@ interface TestConfig { external?: Array; }; + /** + * These settings control whether git information is captured and stored in the config + * [testConfig.metadata](https://playwright.dev/docs/api/class-testconfig#test-config-metadata). + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * captureGitInfo: { commit: true, diff: true } + * }); + * ``` + * + * **Details** + * - Capturing `commit` information is useful when you'd like to see it in your HTML (or a third party) report. + * - Capturing `diff` information is useful to enrich the report with the actual source diff. This information can + * be used to provide intelligent advice on how to fix the test. + * + * **NOTE** Default values for these settings depend on the environment. When tests run as a part of CI where it is + * safe to obtain git information, the default value is `true`, `false` otherwise. + * + * **NOTE** The structure of the git commit metadata is subject to change. + * + */ + captureGitInfo?: { + /** + * Whether to capture commit and pull request information such as hash, author, timestamp. + */ + commit?: boolean; + + /** + * Whether to capture commit diff. + */ + diff?: boolean; + }; + /** * Configuration for the `expect` assertion library. Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts). * @@ -991,6 +1070,27 @@ interface TestConfig { * [YIQ color space](https://en.wikipedia.org/wiki/YIQ) and defaults `threshold` value to `0.2`. */ threshold?: number; + + /** + * A template controlling location of the screenshots. See + * [testConfig.snapshotPathTemplate](https://playwright.dev/docs/api/class-testconfig#test-config-snapshot-path-template) + * for details. + */ + pathTemplate?: string; + }; + + /** + * Configuration for the + * [expect(locator).toMatchAriaSnapshot([options])](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-match-aria-snapshot-2) + * method. + */ + toMatchAriaSnapshot?: { + /** + * A template controlling location of the aria snapshots. See + * [testConfig.snapshotPathTemplate](https://playwright.dev/docs/api/class-testconfig#test-config-snapshot-path-template) + * for details. + */ + pathTemplate?: string; }; /** @@ -1220,7 +1320,8 @@ interface TestConfig { maxFailures?: number; /** - * Metadata that will be put directly to the test report serialized as JSON. + * Metadata contains key-value pairs to be included in the report. For example, HTML report will display it as + * key-value pairs, and JSON report will include metadata serialized as json. * * **Usage** * @@ -1229,7 +1330,7 @@ interface TestConfig { * import { defineConfig } from '@playwright/test'; * * export default defineConfig({ - * metadata: 'acceptance tests', + * metadata: { title: 'acceptance tests' }, * }); * ``` * @@ -1375,7 +1476,7 @@ interface TestConfig { max: number; /** - * Test duration in milliseconds that is considered slow. Defaults to 15 seconds. + * Test file duration in milliseconds that is considered slow. Defaults to 5 minutes. */ threshold: number; }; @@ -1468,10 +1569,14 @@ interface TestConfig { /** * This option configures a template controlling location of snapshots generated by - * [expect(page).toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * [expect(page).toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1), + * [expect(locator).toMatchAriaSnapshot([options])](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-match-aria-snapshot-2) * and * [expect(value).toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1). * + * You can configure templates for each assertion separately in + * [testConfig.expect](https://playwright.dev/docs/api/class-testconfig#test-config-expect). + * * **Usage** * * ```js @@ -1480,7 +1585,19 @@ interface TestConfig { * * export default defineConfig({ * testDir: './tests', + * + * // Single template for all assertions * snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}', + * + * // Assertion-specific templates + * expect: { + * toHaveScreenshot: { + * pathTemplate: '{testDir}/__screenshots__{/projectName}/{testFilePath}/{arg}{ext}', + * }, + * toMatchAriaSnapshot: { + * pathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}', + * }, + * }, * }); * ``` * @@ -1511,27 +1628,27 @@ interface TestConfig { * ``` * * The list of supported tokens: - * - `{arg}` - Relative snapshot path **without extension**. These come from the arguments passed to the - * `toHaveScreenshot()` and `toMatchSnapshot()` calls; if called without arguments, this will be an auto-generated - * snapshot name. + * - `{arg}` - Relative snapshot path **without extension**. This comes from the arguments passed to + * `toHaveScreenshot()`, `toMatchAriaSnapshot()` or `toMatchSnapshot()`; if called without arguments, this will be + * an auto-generated snapshot name. * - Value: `foo/bar/baz` - * - `{ext}` - snapshot extension (with dots) + * - `{ext}` - Snapshot extension (with the leading dot). * - Value: `.png` * - `{platform}` - The value of `process.platform`. * - `{projectName}` - Project's file-system-sanitized name, if any. * - Value: `''` (empty string). * - `{snapshotDir}` - Project's - * [testConfig.snapshotDir](https://playwright.dev/docs/api/class-testconfig#test-config-snapshot-dir). + * [testProject.snapshotDir](https://playwright.dev/docs/api/class-testproject#test-project-snapshot-dir). * - Value: `/home/playwright/tests` (since `snapshotDir` is not provided in config, it defaults to `testDir`) * - `{testDir}` - Project's - * [testConfig.testDir](https://playwright.dev/docs/api/class-testconfig#test-config-test-dir). - * - Value: `/home/playwright/tests` (absolute path is since `testDir` is resolved relative to directory with + * [testProject.testDir](https://playwright.dev/docs/api/class-testproject#test-project-test-dir). + * - Value: `/home/playwright/tests` (absolute path since `testDir` is resolved relative to directory with * config) * - `{testFileDir}` - Directories in relative path from `testDir` to **test file**. * - Value: `page` * - `{testFileName}` - Test file name with extension. * - Value: `page-click.spec.ts` - * - `{testFilePath}` - Relative path from `testDir` to **test file** + * - `{testFilePath}` - Relative path from `testDir` to **test file**. * - Value: `page/page-click.spec.ts` * - `{testName}` - File-system-sanitized test title, including parent describes but excluding file name. * - Value: `suite-test-should-work` @@ -1811,12 +1928,12 @@ export interface FullConfig { */ reportSlowTests: null|{ /** - * The maximum number of slow test files to report. Defaults to `5`. + * The maximum number of slow test files to report. */ max: number; /** - * Test duration in milliseconds that is considered slow. Defaults to 15 seconds. + * Test file duration in milliseconds that is considered slow. */ threshold: number; }; @@ -5711,10 +5828,14 @@ export interface TestType { * @param body Step body. * @param options */ - (title: string, body: () => T | Promise, options?: { box?: boolean, location?: Location, timeout?: number }): Promise; + (title: string, body: (step: TestStepInfo) => T | Promise, options?: { box?: boolean, location?: Location, timeout?: number }): Promise; /** * Mark a test step as "skip" to temporarily disable its execution, useful for steps that are currently failing and - * planned for a near-term fix. Playwright will not run the step. + * planned for a near-term fix. Playwright will not run the step. See also + * [testStepInfo.skip(condition[, description])](https://playwright.dev/docs/api/class-teststepinfo#test-step-info-skip-2). + * + * We recommend [testStepInfo.skip()](https://playwright.dev/docs/api/class-teststepinfo#test-step-info-skip-1) + * instead. * * **Usage** * @@ -5735,7 +5856,7 @@ export interface TestType { * @param body Step body. * @param options */ - skip(title: string, body: () => any | Promise, options?: { box?: boolean, location?: Location, timeout?: number }): Promise; + skip(title: string, body: (step: TestStepInfo) => any | Promise, options?: { box?: boolean, location?: Location, timeout?: number }): Promise; } /** * `expect` function can be used to create test assertions. Read more about [test assertions](https://playwright.dev/docs/test-assertions). @@ -8386,7 +8507,8 @@ interface LocatorAssertions { * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink * box `#FF00FF` (customized by * [`maskColor`](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-have-screenshot-1-option-mask-color)) - * that completely covers its bounding box. + * that completely covers its bounding box. The mask is also applied to invisible elements, see + * [Matching only visible elements](https://playwright.dev/docs/locators#matching-only-visible-elements) to disable that. */ mask?: Array; @@ -8478,7 +8600,8 @@ interface LocatorAssertions { * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink * box `#FF00FF` (customized by * [`maskColor`](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-have-screenshot-2-option-mask-color)) - * that completely covers its bounding box. + * that completely covers its bounding box. The mask is also applied to invisible elements, see + * [Matching only visible elements](https://playwright.dev/docs/locators#matching-only-visible-elements) to disable that. */ mask?: Array; @@ -8685,28 +8808,25 @@ interface LocatorAssertions { /** * Asserts that the target element matches the given [accessibility snapshot](https://playwright.dev/docs/aria-snapshots). * + * Snapshot is stored in a separate `.aria.yml` file in a location configured by + * `expect.toMatchAriaSnapshot.pathTemplate` and/or `snapshotPathTemplate` properties in the configuration file. + * * **Usage** * * ```js * await expect(page.locator('body')).toMatchAriaSnapshot(); - * await expect(page.locator('body')).toMatchAriaSnapshot({ name: 'snapshot' }); - * await expect(page.locator('body')).toMatchAriaSnapshot({ path: '/path/to/snapshot.yml' }); + * await expect(page.locator('body')).toMatchAriaSnapshot({ name: 'body.aria.yml' }); * ``` * * @param options */ toMatchAriaSnapshot(options?: { /** - * Name of the snapshot to store in the snapshot folder corresponding to this test. Generates ordinal name if not + * Name of the snapshot to store in the snapshot folder corresponding to this test. Generates sequential names if not * specified. */ name?: string; - /** - * Path to the YAML snapshot file. - */ - path?: string; - /** * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. */ @@ -8797,17 +8917,33 @@ interface PageAssertions { * **Usage** * * ```js - * await expect(page).toHaveURL(/.*checkout/); + * // Check for the page URL to be 'https://playwright.dev/docs/intro' (including query string) + * await expect(page).toHaveURL('https://playwright.dev/docs/intro'); + * + * // Check for the page URL to contain 'doc', followed by an optional 's', followed by '/' + * await expect(page).toHaveURL(/docs?\//); + * + * // Check for the predicate to be satisfied + * // For example: verify query strings + * await expect(page).toHaveURL(url => { + * const params = url.searchParams; + * return params.has('search') && params.has('options') && params.get('id') === '5'; + * }); * ``` * - * @param urlOrRegExp Expected URL string or RegExp. + * @param url Expected URL string, RegExp, or predicate receiving [URL] to match. When + * [`baseURL`](https://playwright.dev/docs/api/class-browser#browser-new-context-option-base-url) is provided via the + * context options and the `url` argument is a string, the two values are merged via the + * [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor and used for the comparison + * against the current browser URL. * @param options */ - toHaveURL(urlOrRegExp: string|RegExp, options?: { + toHaveURL(url: string|RegExp|((url: URL) => boolean), options?: { /** * Whether to perform case-insensitive match. * [`ignoreCase`](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-url-option-ignore-case) - * option takes precedence over the corresponding regular expression flag if specified. + * option takes precedence over the corresponding regular expression parameter if specified. A provided predicate + * ignores this flag. */ ignoreCase?: boolean; @@ -9452,6 +9588,134 @@ export interface TestInfoError { value?: string; } +/** + * `TestStepInfo` contains information about currently running test step. It is passed as an argument to the step + * function. `TestStepInfo` provides utilities to control test step execution. + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('basic test', async ({ page, browserName }) => { + * await test.step('check some behavior', async step => { + * step.skip(browserName === 'webkit', 'The feature is not available in WebKit'); + * // ... rest of the step code + * }); + * }); + * ``` + * + */ +export interface TestStepInfo { + /** + * Attach a value or a file from disk to the current test step. Some reporters show test step attachments. Either + * [`path`](https://playwright.dev/docs/api/class-teststepinfo#test-step-info-attach-option-path) or + * [`body`](https://playwright.dev/docs/api/class-teststepinfo#test-step-info-attach-option-body) must be specified, + * but not both. Calling this method will attribute the attachment to the step, as opposed to + * [testInfo.attach(name[, options])](https://playwright.dev/docs/api/class-testinfo#test-info-attach) which stores + * all attachments at the test level. + * + * For example, you can attach a screenshot to the test step: + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('basic test', async ({ page }) => { + * await page.goto('https://playwright.dev'); + * await test.step('check page rendering', async step => { + * const screenshot = await page.screenshot(); + * await step.attach('screenshot', { body: screenshot, contentType: 'image/png' }); + * }); + * }); + * ``` + * + * Or you can attach files returned by your APIs: + * + * ```js + * import { test, expect } from '@playwright/test'; + * import { download } from './my-custom-helpers'; + * + * test('basic test', async ({}) => { + * await test.step('check download behavior', async step => { + * const tmpPath = await download('a'); + * await step.attach('downloaded', { path: tmpPath }); + * }); + * }); + * ``` + * + * **NOTE** + * [testStepInfo.attach(name[, options])](https://playwright.dev/docs/api/class-teststepinfo#test-step-info-attach) + * automatically takes care of copying attached files to a location that is accessible to reporters. You can safely + * remove the attachment after awaiting the attach call. + * + * @param name Attachment name. The name will also be sanitized and used as the prefix of file name when saving to disk. + * @param options + */ + attach(name: string, options?: { + /** + * Attachment body. Mutually exclusive with + * [`path`](https://playwright.dev/docs/api/class-teststepinfo#test-step-info-attach-option-path). + */ + body?: string|Buffer; + + /** + * Content type of this attachment to properly present in the report, for example `'application/json'` or + * `'image/png'`. If omitted, content type is inferred based on the + * [`path`](https://playwright.dev/docs/api/class-teststepinfo#test-step-info-attach-option-path), or defaults to + * `text/plain` for [string] attachments and `application/octet-stream` for [Buffer] attachments. + */ + contentType?: string; + + /** + * Path on the filesystem to the attached file. Mutually exclusive with + * [`body`](https://playwright.dev/docs/api/class-teststepinfo#test-step-info-attach-option-body). + */ + path?: string; + }): Promise; + + /** + * Abort the currently running step and mark it as skipped. Useful for steps that are currently failing and planned + * for a near-term fix. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('my test', async ({ page }) => { + * await test.step('check expectations', async step => { + * step.skip(); + * // step body below will not run + * // ... + * }); + * }); + * ``` + * + */ + skip(): void; + + /** + * Conditionally abort the currently running step and mark it as skipped with an optional description. Useful for + * steps that should not be executed in some cases. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('my test', async ({ page, isMobile }) => { + * await test.step('check desktop expectations', async step => { + * step.skip(isMobile, 'not present in the mobile layout'); + * // step body below will not run + * // ... + * }); + * }); + * ``` + * + * @param condition A skip condition. Test step is skipped when the condition is `true`. + * @param description Optional description that will be reflected in a test report. + */ + skip(condition: boolean, description?: string): void; +} + /** * `WorkerInfo` contains information about the worker that is running tests and is available to worker-scoped * fixtures. `WorkerInfo` is a subset of [TestInfo](https://playwright.dev/docs/api/class-testinfo) that is available @@ -9540,7 +9804,8 @@ export interface PageAssertionsToHaveScreenshotOptions { * Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink * box `#FF00FF` (customized by * [`maskColor`](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1-option-mask-color)) - * that completely covers its bounding box. + * that completely covers its bounding box. The mask is also applied to invisible elements, see + * [Matching only visible elements](https://playwright.dev/docs/locators#matching-only-visible-elements) to disable that. */ mask?: Array; @@ -9650,9 +9915,10 @@ interface TestConfigWebServer { /** * How to shut down the process. If unspecified, the process group is forcefully `SIGKILL`ed. If set to `{ signal: - * 'SIGINT', timeout: 500 }`, the process group is sent a `SIGINT` signal, followed by `SIGKILL` if it doesn't exit - * within 500ms. You can also use `SIGTERM` instead. A `0` timeout means no `SIGKILL` will be sent. Windows doesn't - * support `SIGINT` and `SIGTERM` signals, so this option is ignored. + * 'SIGTERM', timeout: 500 }`, the process group is sent a `SIGTERM` signal, followed by `SIGKILL` if it doesn't exit + * within 500ms. You can also use `SIGINT` as the signal instead. A `0` timeout means no `SIGKILL` will be sent. + * Windows doesn't support `SIGTERM` and `SIGINT` signals, so this option is ignored on Windows. Note that shutting + * down a Docker container requires `SIGTERM`. */ gracefulShutdown?: { signal: "SIGINT"|"SIGTERM"; diff --git a/packages/playwright/types/testReporter.d.ts b/packages/playwright/types/testReporter.d.ts index 3f3a43984e802..2abfa9592ec52 100644 --- a/packages/playwright/types/testReporter.d.ts +++ b/packages/playwright/types/testReporter.d.ts @@ -291,6 +291,7 @@ export interface JSONReportError { export interface JSONReportTestResult { workerIndex: number; + parallelIndex: number; status: TestStatus | undefined; duration: number; error: TestError | undefined; @@ -691,6 +692,21 @@ export interface TestStep { */ titlePath(): Array; + /** + * The list of annotations applicable to the current test step. + */ + annotations: Array<{ + /** + * Annotation type, for example `'skip'`. + */ + type: string; + + /** + * Optional description. + */ + description?: string; + }>; + /** * The list of files or buffers attached in the step execution through * [testInfo.attach(name[, options])](https://playwright.dev/docs/api/class-testinfo#test-info-attach). diff --git a/packages/protocol/src/channels.d.ts b/packages/protocol/src/channels.d.ts index 526cc599ab89d..137bc6238f4b2 100644 --- a/packages/protocol/src/channels.d.ts +++ b/packages/protocol/src/channels.d.ts @@ -271,9 +271,40 @@ export type NameValue = { value: string, }; +export type IndexedDBDatabase = { + name: string, + version: number, + stores: { + name: string, + autoIncrement: boolean, + keyPath?: string, + keyPathArray?: string[], + records: { + key?: any, + keyEncoded?: any, + value?: any, + valueEncoded?: any, + }[], + indexes: { + name: string, + keyPath?: string, + keyPathArray?: string[], + multiEntry: boolean, + unique: boolean, + }[], + }[], +}; + +export type SetOriginStorage = { + origin: string, + localStorage: NameValue[], + indexedDB?: IndexedDBDatabase[], +}; + export type OriginStorage = { origin: string, localStorage: NameValue[], + indexedDB?: IndexedDBDatabase[], }; export type SerializedError = { @@ -315,7 +346,7 @@ export interface APIRequestContextChannel extends APIRequestContextEventTarget, fetch(params: APIRequestContextFetchParams, metadata?: CallMetadata): Promise; fetchResponseBody(params: APIRequestContextFetchResponseBodyParams, metadata?: CallMetadata): Promise; fetchLog(params: APIRequestContextFetchLogParams, metadata?: CallMetadata): Promise; - storageState(params?: APIRequestContextStorageStateParams, metadata?: CallMetadata): Promise; + storageState(params: APIRequestContextStorageStateParams, metadata?: CallMetadata): Promise; disposeAPIResponse(params: APIRequestContextDisposeAPIResponseParams, metadata?: CallMetadata): Promise; dispose(params: APIRequestContextDisposeParams, metadata?: CallMetadata): Promise; } @@ -371,8 +402,12 @@ export type APIRequestContextFetchLogOptions = { export type APIRequestContextFetchLogResult = { log: string[], }; -export type APIRequestContextStorageStateParams = {}; -export type APIRequestContextStorageStateOptions = {}; +export type APIRequestContextStorageStateParams = { + indexedDB?: boolean, +}; +export type APIRequestContextStorageStateOptions = { + indexedDB?: boolean, +}; export type APIRequestContextStorageStateResult = { cookies: NetworkCookie[], origins: OriginStorage[], @@ -588,6 +623,7 @@ export type PlaywrightNewRequestParams = { userAgent?: string, ignoreHTTPSErrors?: boolean, extraHTTPHeaders?: NameValue[], + failOnStatusCode?: boolean, clientCertificates?: { origin: string, cert?: Binary, @@ -610,7 +646,7 @@ export type PlaywrightNewRequestParams = { timeout?: number, storageState?: { cookies?: NetworkCookie[], - origins?: OriginStorage[], + origins?: SetOriginStorage[], }, tracesDir?: string, }; @@ -619,6 +655,7 @@ export type PlaywrightNewRequestOptions = { userAgent?: string, ignoreHTTPSErrors?: boolean, extraHTTPHeaders?: NameValue[], + failOnStatusCode?: boolean, clientCertificates?: { origin: string, cert?: Binary, @@ -641,7 +678,7 @@ export type PlaywrightNewRequestOptions = { timeout?: number, storageState?: { cookies?: NetworkCookie[], - origins?: OriginStorage[], + origins?: SetOriginStorage[], }, tracesDir?: string, }; @@ -1006,6 +1043,7 @@ export type BrowserTypeLaunchPersistentContextParams = { reducedMotion?: 'reduce' | 'no-preference' | 'no-override', forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: 'accept' | 'deny' | 'internal-browser-default', + contrast?: 'no-preference' | 'more' | 'no-override', baseURL?: string, recordVideo?: { dir: string, @@ -1086,6 +1124,7 @@ export type BrowserTypeLaunchPersistentContextOptions = { reducedMotion?: 'reduce' | 'no-preference' | 'no-override', forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: 'accept' | 'deny' | 'internal-browser-default', + contrast?: 'no-preference' | 'more' | 'no-override', baseURL?: string, recordVideo?: { dir: string, @@ -1201,6 +1240,7 @@ export type BrowserNewContextParams = { reducedMotion?: 'reduce' | 'no-preference' | 'no-override', forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: 'accept' | 'deny' | 'internal-browser-default', + contrast?: 'no-preference' | 'more' | 'no-override', baseURL?: string, recordVideo?: { dir: string, @@ -1220,7 +1260,7 @@ export type BrowserNewContextParams = { }, storageState?: { cookies?: SetNetworkCookie[], - origins?: OriginStorage[], + origins?: SetOriginStorage[], }, }; export type BrowserNewContextOptions = { @@ -1267,6 +1307,7 @@ export type BrowserNewContextOptions = { reducedMotion?: 'reduce' | 'no-preference' | 'no-override', forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: 'accept' | 'deny' | 'internal-browser-default', + contrast?: 'no-preference' | 'more' | 'no-override', baseURL?: string, recordVideo?: { dir: string, @@ -1286,7 +1327,7 @@ export type BrowserNewContextOptions = { }, storageState?: { cookies?: SetNetworkCookie[], - origins?: OriginStorage[], + origins?: SetOriginStorage[], }, }; export type BrowserNewContextResult = { @@ -1336,6 +1377,7 @@ export type BrowserNewContextForReuseParams = { reducedMotion?: 'reduce' | 'no-preference' | 'no-override', forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: 'accept' | 'deny' | 'internal-browser-default', + contrast?: 'no-preference' | 'more' | 'no-override', baseURL?: string, recordVideo?: { dir: string, @@ -1355,7 +1397,7 @@ export type BrowserNewContextForReuseParams = { }, storageState?: { cookies?: SetNetworkCookie[], - origins?: OriginStorage[], + origins?: SetOriginStorage[], }, }; export type BrowserNewContextForReuseOptions = { @@ -1402,6 +1444,7 @@ export type BrowserNewContextForReuseOptions = { reducedMotion?: 'reduce' | 'no-preference' | 'no-override', forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: 'accept' | 'deny' | 'internal-browser-default', + contrast?: 'no-preference' | 'more' | 'no-override', baseURL?: string, recordVideo?: { dir: string, @@ -1421,7 +1464,7 @@ export type BrowserNewContextForReuseOptions = { }, storageState?: { cookies?: SetNetworkCookie[], - origins?: OriginStorage[], + origins?: SetOriginStorage[], }, }; export type BrowserNewContextForReuseResult = { @@ -1527,7 +1570,7 @@ export interface BrowserContextChannel extends BrowserContextEventTarget, EventT setNetworkInterceptionPatterns(params: BrowserContextSetNetworkInterceptionPatternsParams, metadata?: CallMetadata): Promise; setWebSocketInterceptionPatterns(params: BrowserContextSetWebSocketInterceptionPatternsParams, metadata?: CallMetadata): Promise; setOffline(params: BrowserContextSetOfflineParams, metadata?: CallMetadata): Promise; - storageState(params?: BrowserContextStorageStateParams, metadata?: CallMetadata): Promise; + storageState(params: BrowserContextStorageStateParams, metadata?: CallMetadata): Promise; pause(params?: BrowserContextPauseParams, metadata?: CallMetadata): Promise; enableRecorder(params: BrowserContextEnableRecorderParams, metadata?: CallMetadata): Promise; newCDPSession(params: BrowserContextNewCDPSessionParams, metadata?: CallMetadata): Promise; @@ -1760,8 +1803,12 @@ export type BrowserContextSetOfflineOptions = { }; export type BrowserContextSetOfflineResult = void; -export type BrowserContextStorageStateParams = {}; -export type BrowserContextStorageStateOptions = {}; +export type BrowserContextStorageStateParams = { + indexedDB?: boolean, +}; +export type BrowserContextStorageStateOptions = { + indexedDB?: boolean, +}; export type BrowserContextStorageStateResult = { cookies: NetworkCookie[], origins: OriginStorage[], @@ -2063,12 +2110,14 @@ export type PageEmulateMediaParams = { colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', reducedMotion?: 'reduce' | 'no-preference' | 'no-override', forcedColors?: 'active' | 'none' | 'no-override', + contrast?: 'no-preference' | 'more' | 'no-override', }; export type PageEmulateMediaOptions = { media?: 'screen' | 'print' | 'no-override', colorScheme?: 'dark' | 'light' | 'no-preference' | 'no-override', reducedMotion?: 'reduce' | 'no-preference' | 'no-override', forcedColors?: 'active' | 'none' | 'no-override', + contrast?: 'no-preference' | 'more' | 'no-override', }; export type PageEmulateMediaResult = void; export type PageExposeBindingParams = { @@ -2619,9 +2668,13 @@ export type FrameAddStyleTagResult = { }; export type FrameAriaSnapshotParams = { selector: string, + id?: boolean, + mode?: 'raw' | 'regex', timeout?: number, }; export type FrameAriaSnapshotOptions = { + id?: boolean, + mode?: 'raw' | 'regex', timeout?: number, }; export type FrameAriaSnapshotResult = { @@ -3311,6 +3364,7 @@ export interface ElementHandleChannel extends ElementHandleEventTarget, JSHandle dispatchEvent(params: ElementHandleDispatchEventParams, metadata?: CallMetadata): Promise; fill(params: ElementHandleFillParams, metadata?: CallMetadata): Promise; focus(params?: ElementHandleFocusParams, metadata?: CallMetadata): Promise; + generateLocatorString(params?: ElementHandleGenerateLocatorStringParams, metadata?: CallMetadata): Promise; getAttribute(params: ElementHandleGetAttributeParams, metadata?: CallMetadata): Promise; hover(params: ElementHandleHoverParams, metadata?: CallMetadata): Promise; innerHTML(params?: ElementHandleInnerHTMLParams, metadata?: CallMetadata): Promise; @@ -3450,6 +3504,11 @@ export type ElementHandleFillResult = void; export type ElementHandleFocusParams = {}; export type ElementHandleFocusOptions = {}; export type ElementHandleFocusResult = void; +export type ElementHandleGenerateLocatorStringParams = {}; +export type ElementHandleGenerateLocatorStringOptions = {}; +export type ElementHandleGenerateLocatorStringResult = { + value?: string, +}; export type ElementHandleGetAttributeParams = { name: string, }; @@ -4751,6 +4810,7 @@ export type AndroidDeviceLaunchBrowserParams = { reducedMotion?: 'reduce' | 'no-preference' | 'no-override', forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: 'accept' | 'deny' | 'internal-browser-default', + contrast?: 'no-preference' | 'more' | 'no-override', baseURL?: string, recordVideo?: { dir: string, @@ -4815,6 +4875,7 @@ export type AndroidDeviceLaunchBrowserOptions = { reducedMotion?: 'reduce' | 'no-preference' | 'no-override', forcedColors?: 'active' | 'none' | 'no-override', acceptDownloads?: 'accept' | 'deny' | 'internal-browser-default', + contrast?: 'no-preference' | 'more' | 'no-override', baseURL?: string, recordVideo?: { dir: string, diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index df54dcbe1ca0f..e45b01ddebb14 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -222,6 +222,54 @@ NameValue: name: string value: string +IndexedDBDatabase: + type: object + properties: + name: string + version: number + stores: + type: array + items: + type: object + properties: + name: string + autoIncrement: boolean + keyPath: string? + keyPathArray: + type: array? + items: string + records: + type: array + items: + type: object + properties: + key: json? + keyEncoded: json? + value: json? + valueEncoded: json? + indexes: + type: array + items: + type: object + properties: + name: string + keyPath: string? + keyPathArray: + type: array? + items: string + multiEntry: boolean + unique: boolean + +SetOriginStorage: + type: object + properties: + origin: string + localStorage: + type: array + items: NameValue + indexedDB: + type: array? + items: IndexedDBDatabase OriginStorage: type: object @@ -230,7 +278,9 @@ OriginStorage: localStorage: type: array items: NameValue - + indexedDB: + type: array? + items: IndexedDBDatabase SerializedError: type: object @@ -326,6 +376,8 @@ APIRequestContext: items: string storageState: + parameters: + indexedDB: boolean? returns: cookies: type: array @@ -508,6 +560,12 @@ ContextOptions: - accept - deny - internal-browser-default + contrast: + type: enum? + literals: + - no-preference + - more + - no-override baseURL: string? recordVideo: type: object? @@ -693,6 +751,7 @@ Playwright: extraHTTPHeaders: type: array? items: NameValue + failOnStatusCode: boolean? clientCertificates: type: array? items: @@ -730,7 +789,7 @@ Playwright: items: NetworkCookie origins: type: array? - items: OriginStorage + items: SetOriginStorage tracesDir: string? returns: @@ -964,7 +1023,7 @@ Browser: items: SetNetworkCookie origins: type: array? - items: OriginStorage + items: SetOriginStorage returns: context: BrowserContext @@ -986,7 +1045,7 @@ Browser: items: SetNetworkCookie origins: type: array? - items: OriginStorage + items: SetOriginStorage returns: context: BrowserContext @@ -1178,6 +1237,8 @@ BrowserContext: offline: boolean storageState: + parameters: + indexedDB: boolean? returns: cookies: type: array @@ -1420,6 +1481,12 @@ Page: - active - none - no-override + contrast: + type: enum? + literals: + - no-preference + - more + - no-override flags: snapshot: true @@ -1879,6 +1946,12 @@ Frame: ariaSnapshot: parameters: selector: string + id: boolean? + mode: + type: enum? + literals: + - raw + - regex timeout: number? returns: snapshot: string @@ -2648,6 +2721,10 @@ ElementHandle: slowMo: true snapshot: true + generateLocatorString: + returns: + value: string? + getAttribute: parameters: name: string diff --git a/packages/recorder/src/main.tsx b/packages/recorder/src/main.tsx index 61ac9da67fb7e..4ecfc977600ab 100644 --- a/packages/recorder/src/main.tsx +++ b/packages/recorder/src/main.tsx @@ -19,29 +19,33 @@ import * as React from 'react'; import { Recorder } from './recorder'; import './recorder.css'; -export const Main: React.FC = ({ -}) => { +export const Main: React.FC = ({}) => { const [sources, setSources] = React.useState([]); const [paused, setPaused] = React.useState(false); const [log, setLog] = React.useState(new Map()); const [mode, setMode] = React.useState('none'); - window.playwrightSetMode = setMode; - window.playwrightSetSources = React.useCallback((sources: Source[]) => { - setSources(sources); - window.playwrightSourcesEchoForTest = sources; + React.useLayoutEffect(() => { + window.playwrightSetMode = setMode; + window.playwrightSetSources = (sources, primaryPageURL) => { + setSources(sources); + window.playwrightSourcesEchoForTest = sources; + document.title = primaryPageURL + ? `Playwright Inspector - ${primaryPageURL}` + : `Playwright Inspector`; + }; + window.playwrightSetPaused = setPaused; + window.playwrightUpdateLogs = callLogs => { + setLog(log => { + const newLog = new Map(log); + for (const callLog of callLogs) { + callLog.reveal = !log.has(callLog.id); + newLog.set(callLog.id, callLog); + } + return newLog; + }); + }; }, []); - window.playwrightSetPaused = setPaused; - window.playwrightUpdateLogs = callLogs => { - setLog(log => { - const newLog = new Map(log); - for (const callLog of callLogs) { - callLog.reveal = !log.has(callLog.id); - newLog.set(callLog.id, callLog); - } - return newLog; - }); - }; return ; }; diff --git a/packages/recorder/src/recorderTypes.d.ts b/packages/recorder/src/recorderTypes.d.ts index 22561608aed97..ae4c41f4f7fc8 100644 --- a/packages/recorder/src/recorderTypes.d.ts +++ b/packages/recorder/src/recorderTypes.d.ts @@ -101,7 +101,7 @@ declare global { interface Window { playwrightSetMode: (mode: Mode) => void; playwrightSetPaused: (paused: boolean) => void; - playwrightSetSources: (sources: Source[]) => void; + playwrightSetSources: (sources: Source[], primaryPageURL: string | undefined) => void; playwrightSetOverlayVisible: (visible: boolean) => void; playwrightUpdateLogs: (callLogs: CallLog[]) => void; playwrightSetRunningFile: (file: string | undefined) => void; diff --git a/packages/recorder/tsconfig.json b/packages/recorder/tsconfig.json index 16546d6e0de1c..166ee1a010ca1 100644 --- a/packages/recorder/tsconfig.json +++ b/packages/recorder/tsconfig.json @@ -5,11 +5,11 @@ "lib": ["DOM", "DOM.Iterable", "ESNext"], "allowJs": true, "skipLibCheck": false, - "esModuleInterop": false, + "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "module": "ESNext", - "moduleResolution": "Node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, @@ -23,6 +23,6 @@ "@web/*": ["../web/src/*"], } }, - "include": ["src"], + "include": ["src", "../web/src"], "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/packages/recorder/vite.config.ts b/packages/recorder/vite.config.ts index a72a43f203731..17468bdc6971e 100644 --- a/packages/recorder/vite.config.ts +++ b/packages/recorder/vite.config.ts @@ -16,7 +16,7 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; -import * as path from 'path'; +import path from 'path'; // https://vitejs.dev/config/ export default defineConfig({ diff --git a/packages/trace-viewer/package.json b/packages/trace-viewer/package.json index 57a3dfd4094f3..fde4eb6766a7c 100644 --- a/packages/trace-viewer/package.json +++ b/packages/trace-viewer/package.json @@ -4,6 +4,7 @@ "version": "0.0.0", "type": "module", "dependencies": { - "yaml": "^2.6.0" + "yaml": "^2.6.0", + "markdown-to-jsx": "^7.7.3" } } diff --git a/packages/trace-viewer/src/sw/main.ts b/packages/trace-viewer/src/sw/main.ts index cda3ba8cadb91..cdce3261feac0 100644 --- a/packages/trace-viewer/src/sw/main.ts +++ b/packages/trace-viewer/src/sw/main.ts @@ -78,6 +78,12 @@ async function doFetch(event: FetchEvent): Promise { if (event.request.url.startsWith('chrome-extension://')) return fetch(event.request); + if (event.request.headers.get('x-pw-serviceworker') === 'forward') { + const request = new Request(event.request); + request.headers.delete('x-pw-serviceworker'); + return fetch(request); + } + const request = event.request; const client = await self.clients.get(event.clientId); @@ -120,14 +126,16 @@ async function doFetch(event: FetchEvent): Promise { const { snapshotServer } = loadedTraces.get(traceUrl!) || {}; if (!snapshotServer) return new Response(null, { status: 404 }); - return snapshotServer.serveSnapshotInfo(relativePath, url.searchParams); + const pageOrFrameId = relativePath.substring('/snapshotInfo/'.length); + return snapshotServer.serveSnapshotInfo(pageOrFrameId, url.searchParams); } if (relativePath.startsWith('/snapshot/')) { const { snapshotServer } = loadedTraces.get(traceUrl!) || {}; if (!snapshotServer) return new Response(null, { status: 404 }); - const response = snapshotServer.serveSnapshot(relativePath, url.searchParams, url.href); + const pageOrFrameId = relativePath.substring('/snapshot/'.length); + const response = snapshotServer.serveSnapshot(pageOrFrameId, url.searchParams, url.href); if (isDeployedAsHttps) response.headers.set('Content-Security-Policy', 'upgrade-insecure-requests'); return response; @@ -137,7 +145,8 @@ async function doFetch(event: FetchEvent): Promise { const { snapshotServer } = loadedTraces.get(traceUrl!) || {}; if (!snapshotServer) return new Response(null, { status: 404 }); - return snapshotServer.serveClosestScreenshot(relativePath, url.searchParams); + const pageOrFrameId = relativePath.substring('/closest-screenshot/'.length); + return snapshotServer.serveClosestScreenshot(pageOrFrameId, url.searchParams); } if (relativePath.startsWith('/sha1/')) { diff --git a/packages/trace-viewer/src/sw/snapshotServer.ts b/packages/trace-viewer/src/sw/snapshotServer.ts index e1978c79b62e0..64a86935402f7 100644 --- a/packages/trace-viewer/src/sw/snapshotServer.ts +++ b/packages/trace-viewer/src/sw/snapshotServer.ts @@ -31,8 +31,8 @@ export class SnapshotServer { this._resourceLoader = resourceLoader; } - serveSnapshot(pathname: string, searchParams: URLSearchParams, snapshotUrl: string): Response { - const snapshot = this._snapshot(pathname.substring('/snapshot'.length), searchParams); + serveSnapshot(pageOrFrameId: string, searchParams: URLSearchParams, snapshotUrl: string): Response { + const snapshot = this._snapshot(pageOrFrameId, searchParams); if (!snapshot) return new Response(null, { status: 404 }); @@ -41,16 +41,16 @@ export class SnapshotServer { return new Response(renderedSnapshot.html, { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' } }); } - async serveClosestScreenshot(pathname: string, searchParams: URLSearchParams): Promise { - const snapshot = this._snapshot(pathname.substring('/closest-screenshot'.length), searchParams); + async serveClosestScreenshot(pageOrFrameId: string, searchParams: URLSearchParams): Promise { + const snapshot = this._snapshot(pageOrFrameId, searchParams); const sha1 = snapshot?.closestScreenshot(); if (!sha1) return new Response(null, { status: 404 }); return new Response(await this._resourceLoader(sha1)); } - serveSnapshotInfo(pathname: string, searchParams: URLSearchParams): Response { - const snapshot = this._snapshot(pathname.substring('/snapshotInfo'.length), searchParams); + serveSnapshotInfo(pageOrFrameId: string, searchParams: URLSearchParams): Response { + const snapshot = this._snapshot(pageOrFrameId, searchParams); return this._respondWithJson(snapshot ? { viewport: snapshot.viewport(), url: snapshot.snapshot().frameUrl, @@ -61,9 +61,9 @@ export class SnapshotServer { }); } - private _snapshot(pathname: string, params: URLSearchParams) { + private _snapshot(pageOrFrameId: string, params: URLSearchParams) { const name = params.get('name')!; - return this._snapshotStorage.snapshotByName(pathname.slice(1), name); + return this._snapshotStorage.snapshotByName(pageOrFrameId, name); } private _respondWithJson(object: any): Response { diff --git a/packages/trace-viewer/src/sw/snapshotStorage.ts b/packages/trace-viewer/src/sw/snapshotStorage.ts index d15bfc4f41674..a0adadefb1223 100644 --- a/packages/trace-viewer/src/sw/snapshotStorage.ts +++ b/packages/trace-viewer/src/sw/snapshotStorage.ts @@ -20,19 +20,19 @@ import type { PageEntry } from '../types/entries'; import { LRUCache } from './lruCache'; export class SnapshotStorage { - private _resources: ResourceSnapshot[] = []; private _frameSnapshots = new Map(); private _cache = new LRUCache(100_000_000); // 100MB per each trace + private _contextToResources = new Map(); - addResource(resource: ResourceSnapshot): void { + addResource(contextId: string, resource: ResourceSnapshot): void { resource.request.url = rewriteURLForCustomProtocol(resource.request.url); - this._resources.push(resource); + this._ensureResourcesForContext(contextId).push(resource); } - addFrameSnapshot(snapshot: FrameSnapshot, screencastFrames: PageEntry['screencastFrames']) { + addFrameSnapshot(contextId: string, snapshot: FrameSnapshot, screencastFrames: PageEntry['screencastFrames']) { for (const override of snapshot.resourceOverrides) override.url = rewriteURLForCustomProtocol(override.url); let frameSnapshots = this._frameSnapshots.get(snapshot.frameId); @@ -46,7 +46,8 @@ export class SnapshotStorage { this._frameSnapshots.set(snapshot.pageId, frameSnapshots); } frameSnapshots.raw.push(snapshot); - const renderer = new SnapshotRenderer(this._cache, this._resources, frameSnapshots.raw, screencastFrames, frameSnapshots.raw.length - 1); + const resources = this._ensureResourcesForContext(contextId); + const renderer = new SnapshotRenderer(this._cache, resources, frameSnapshots.raw, screencastFrames, frameSnapshots.raw.length - 1); frameSnapshots.renderers.push(renderer); return renderer; } @@ -62,6 +63,16 @@ export class SnapshotStorage { finalize() { // Resources are not necessarily sorted in the trace file, so sort them now. - this._resources.sort((a, b) => (a._monotonicTime || 0) - (b._monotonicTime || 0)); + for (const resources of this._contextToResources.values()) + resources.sort((a, b) => (a._monotonicTime || 0) - (b._monotonicTime || 0)); + } + + private _ensureResourcesForContext(contextId: string): ResourceSnapshot[] { + let resources = this._contextToResources.get(contextId); + if (!resources) { + resources = []; + this._contextToResources.set(contextId, resources); + } + return resources; } } diff --git a/packages/trace-viewer/src/sw/traceModel.ts b/packages/trace-viewer/src/sw/traceModel.ts index 602ff4e075284..012c7e5bb0950 100644 --- a/packages/trace-viewer/src/sw/traceModel.ts +++ b/packages/trace-viewer/src/sw/traceModel.ts @@ -43,7 +43,7 @@ export class TraceModel { const ordinals: string[] = []; let hasSource = false; for (const entryName of await this._backend.entryNames()) { - const match = entryName.match(/(.+)\.trace/); + const match = entryName.match(/(.+)\.trace$/); if (match) ordinals.push(match[1] || ''); if (entryName.includes('src@')) @@ -105,7 +105,7 @@ export class TraceModel { this.contextEntries.push(contextEntry); } - this._snapshotStorage!.finalize(); + this._snapshotStorage.finalize(); } async hasEntry(filename: string): Promise { @@ -153,5 +153,6 @@ function createEmptyContext(): ContextEntry { errors: [], stdio: [], hasSource: false, + contextId: '', }; } diff --git a/packages/trace-viewer/src/sw/traceModernizer.ts b/packages/trace-viewer/src/sw/traceModernizer.ts index 80f98762dbe46..16bf3ad2dbe5d 100644 --- a/packages/trace-viewer/src/sw/traceModernizer.ts +++ b/packages/trace-viewer/src/sw/traceModernizer.ts @@ -92,6 +92,7 @@ export class TraceModernizer { contextEntry.sdkLanguage = event.sdkLanguage; contextEntry.options = event.options; contextEntry.testIdAttributeName = event.testIdAttributeName; + contextEntry.contextId = event.contextId ?? ''; break; } case 'screencast-frame': { @@ -126,6 +127,7 @@ export class TraceModernizer { existing!.result = event.result; existing!.error = event.error; existing!.attachments = event.attachments; + existing!.annotations = event.annotations; if (event.point) existing!.point = event.point; break; @@ -155,11 +157,11 @@ export class TraceModernizer { break; } case 'resource-snapshot': - this._snapshotStorage.addResource(event.snapshot); + this._snapshotStorage.addResource(this._contextEntry.contextId, event.snapshot); contextEntry.resources.push(event.snapshot); break; case 'frame-snapshot': - this._snapshotStorage.addFrameSnapshot(event.snapshot, this._pageEntry(event.snapshot.pageId).screencastFrames); + this._snapshotStorage.addFrameSnapshot(this._contextEntry.contextId, event.snapshot, this._pageEntry(event.snapshot.pageId).screencastFrames); break; } // Make sure there is a page entry for each page, even without screencast frames, @@ -387,12 +389,13 @@ export class TraceModernizer { wallTime: 0, monotonicTime: 0, sdkLanguage: 'javascript', + contextId: '', }; result.push(event); } for (const event of events) { if (event.type === 'context-options') { - result.push({ ...event, monotonicTime: 0, origin: 'library' }); + result.push({ ...event, monotonicTime: 0, origin: 'library', contextId: '' }); continue; } // Take wall and monotonic time from the first event. diff --git a/packages/trace-viewer/src/types/entries.ts b/packages/trace-viewer/src/types/entries.ts index e7b7a0b9778f9..a28efe402675e 100644 --- a/packages/trace-viewer/src/types/entries.ts +++ b/packages/trace-viewer/src/types/entries.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { Language } from 'playwright-core/src/utils/isomorphic/locatorGenerators'; +import type { Language } from '../../../playwright-core/src/utils/isomorphic/locatorGenerators'; import type { ResourceSnapshot } from '@trace/snapshot'; import type * as trace from '@trace/trace'; @@ -40,6 +40,7 @@ export type ContextEntry = { stdio: trace.StdioTraceEvent[]; errors: trace.ErrorTraceEvent[]; hasSource: boolean; + contextId: string; }; export type PageEntry = { diff --git a/packages/trace-viewer/src/ui/actionList.css b/packages/trace-viewer/src/ui/actionList.css index 0cb3cb5f5469f..f167352593b60 100644 --- a/packages/trace-viewer/src/ui/actionList.css +++ b/packages/trace-viewer/src/ui/actionList.css @@ -41,6 +41,10 @@ color: var(--vscode-editorCodeLens-foreground); } +.action-skipped { + margin-right: 4px; +} + .action-icon { flex: none; display: flex; diff --git a/packages/trace-viewer/src/ui/actionList.tsx b/packages/trace-viewer/src/ui/actionList.tsx index 87e78416b0fb0..4f3a8128e88fd 100644 --- a/packages/trace-viewer/src/ui/actionList.tsx +++ b/packages/trace-viewer/src/ui/actionList.tsx @@ -15,7 +15,7 @@ */ import type { ActionTraceEvent, AfterActionTraceEventAttachment } from '@trace/trace'; -import { msToString } from '@web/uiUtils'; +import { clsx, msToString } from '@web/uiUtils'; import * as React from 'react'; import './actionList.css'; import * as modelUtil from './modelUtil'; @@ -25,6 +25,7 @@ import { TreeView } from '@web/components/treeView'; import type { ActionTraceEventInContext, ActionTreeItem } from './modelUtil'; import type { Boundaries } from './geometry'; import { ToolbarButton } from '@web/components/toolbarButton'; +import { testStatusIcon } from './testUtils'; export interface ActionListProps { actions: ActionTraceEventInContext[], @@ -119,6 +120,7 @@ export const renderAction = ( const parameterString = actionParameterDisplayString(action, sdkLanguage || 'javascript'); + const isSkipped = action.class === 'Test' && action.method === 'step' && action.annotations?.some(a => a.type === 'skip'); let time: string = ''; if (action.endTime) time = msToString(action.endTime - action.startTime); @@ -149,9 +151,10 @@ export const renderAction = ( {action.method === 'goto' && action.params.url &&
{action.params.url}
} {action.class === 'APIRequestContext' && action.params.url &&
{excludeOrigin(action.params.url)}
} - {(showDuration || showBadges || showAttachments) &&
} + {(showDuration || showBadges || showAttachments || isSkipped) &&
} {showAttachments && revealAttachment(action.attachments![0])} />} - {showDuration &&
{time || }
} + {showDuration && !isSkipped &&
{time || }
} + {isSkipped && } {showBadges &&
revealConsole?.()}> {!!errors &&
{errors}
} {!!warnings &&
{warnings}
} diff --git a/packages/trace-viewer/src/ui/aiConversation.css b/packages/trace-viewer/src/ui/aiConversation.css new file mode 100644 index 0000000000000..214496017abec --- /dev/null +++ b/packages/trace-viewer/src/ui/aiConversation.css @@ -0,0 +1,128 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.chat-container { + flex: 1; + display: flex; + flex-direction: column; + justify-content: space-between; + color: #e0e0e0; +} + +.chat-disclaimer { + text-align: center; + color: var(--vscode-editorBracketMatch-border); + margin: 0px; +} + +.chat-container hr { + width: 100%; + border: none; + border-top: 1px solid var(--vscode-titleBar-inactiveBackground); +} + +.messages-container { + flex: 1; + overflow-y: auto; + padding: 16px; + + display: flex; + flex-direction: column; + gap: 16px; +} + +.message { + gap: 12px; + max-width: 85%; +} + +.user-message { + flex-direction: row-reverse; + margin-left: auto; + width: fit-content +} + +.message-icon { + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + background-color: var(--vscode-titleBar-inactiveBackground); + flex-shrink: 0; +} + +.message-content { + background-color: var(--vscode-titleBar-inactiveBackground); + color: var(--vscode-titleBar-activeForeground); + padding: 2px 8px; +} + +.message-content pre { + text-wrap: auto; + overflow-wrap: anywhere; +} + +.user-message .message-content { + background-color: var(--vscode-titleBar-activeBackground); +} + +/* Input form styles */ +.input-form { + position: sticky; + bottom: 0; + display: flex; + height: 64px; + gap: 8px; + padding: 10px; + background-color: var(--vscode-sideBar-background); + border-top: 1px solid var(--vscode-sideBarSectionHeader-border); +} + +.message-input { + flex: 1; + padding: 8px 12px; + border: 1px solid var(--vscode-settings-textInputBorder); + background-color: var(--vscode-settings-textInputBackground); + font-size: 14px; + outline: none; + transition: border-color 0.2s; +} + +.message-input:focus { + border-color: #0078d4; +} + +.send-button { + display: flex; + align-items: center; + justify-content: center; + padding: 8px; + background-color: var(--vscode-button-background); + border: none; + color: white; + cursor: pointer; + transition: background-color 0.2s; +} + +.send-button:hover { + background-color: var(--vscode-button-hoverBackground); +} + +.send-button:disabled { + background-color: var(--vscode-disabledForeground); + cursor: not-allowed; +} diff --git a/packages/trace-viewer/src/ui/aiConversation.tsx b/packages/trace-viewer/src/ui/aiConversation.tsx new file mode 100644 index 0000000000000..548ed626f026c --- /dev/null +++ b/packages/trace-viewer/src/ui/aiConversation.tsx @@ -0,0 +1,84 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { useCallback, useState } from 'react'; +import Markdown from 'markdown-to-jsx'; +import './aiConversation.css'; +import { clsx } from '@web/uiUtils'; +import { useLLMConversation } from './llm'; + +export function AIConversation({ conversationId }: { conversationId: string }) { + const [history, conversation] = useLLMConversation(conversationId); + const [input, setInput] = useState(''); + + const onSubmit = useCallback(() => { + setInput(content => { + conversation.send(content); + return ''; + }); + }, [conversation]); + + return ( +
+

Chat based on {conversation.chat.api.name}. Check for mistakes.

+
+
+ {history.filter(({ role }) => role !== 'developer').map((message, index) => ( +
+ {message.role === 'assistant' && ( +
+ +
+ )} +
+ {message.displayContent ?? message.content} +
+
+ ))} +
+ +
+ `); + await checkAndMatchSnapshot(page.locator('body'), ` + - textbox: Before + `); + await page.evaluate(() => { + document.querySelector('textarea').value = 'After'; + }); + await checkAndMatchSnapshot(page.locator('body'), ` + - textbox: After + `); +}); diff --git a/tests/page/page-check.spec.ts b/tests/page/page-check.spec.ts index 42946ce555f02..01b00ddc55c90 100644 --- a/tests/page/page-check.spec.ts +++ b/tests/page/page-check.spec.ts @@ -18,10 +18,9 @@ import { test as it, expect } from './pageTest'; it('should check the box @smoke', async ({ page }) => { - await page.setContent(`
`); - const locator = page.locator('#component'); - await expect(locator).toHaveClass(/(^|\s)selected(\s|$)/); - await expect(locator).toHaveClass('middle selected row'); + await page.setContent(``); + await page.check('input'); + expect(await page.evaluate(() => window['checkbox'].checked)).toBe(true); }); it('should not check the checked box', async ({ page }) => { diff --git a/tests/page/page-emulate-media.spec.ts b/tests/page/page-emulate-media.spec.ts index c895d64eff789..734bda766b1ca 100644 --- a/tests/page/page-emulate-media.spec.ts +++ b/tests/page/page-emulate-media.spec.ts @@ -15,7 +15,24 @@ * limitations under the License. */ -import { test as it, expect } from './pageTest'; +import type { Page } from 'packages/playwright-test'; +import { test as it, expect as baseExpect } from './pageTest'; + +const expect = baseExpect.extend({ + async toMatchMedia(page: Page, mediaQuery: string) { + const pass = await page.evaluate(mediaQuery => matchMedia(mediaQuery).matches, mediaQuery).catch(() => false); + return { + message() { + if (pass) + return `Expected "${mediaQuery}" not to match, but it did`; + else + return `Expected "${mediaQuery}" to match, but it did not`; + }, + pass, + name: 'toMatchMedia', + }; + }, +}); it('should emulate type @smoke', async ({ page }) => { expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(true); @@ -158,3 +175,15 @@ it('should emulate forcedColors ', async ({ page, browserName }) => { await page.emulateMedia({ forcedColors: null }); expect(await page.evaluate(() => matchMedia('(forced-colors: none)').matches)).toBe(true); }); + +it('should emulate contrast ', async ({ page }) => { + await expect(page).toMatchMedia('(prefers-contrast: no-preference)'); + await page.emulateMedia({ contrast: 'no-preference' }); + await expect(page).toMatchMedia('(prefers-contrast: no-preference)'); + await expect(page).not.toMatchMedia('(prefers-contrast: more)'); + await page.emulateMedia({ contrast: 'more' }); + await expect(page).not.toMatchMedia('(prefers-contrast: no-preference)'); + await expect(page).toMatchMedia('(prefers-contrast: more)'); + await page.emulateMedia({ contrast: null }); + await expect(page).toMatchMedia('(prefers-contrast: no-preference)'); +}); diff --git a/tests/page/page-event-request.spec.ts b/tests/page/page-event-request.spec.ts index e1fc29eb59515..84717026a8ef6 100644 --- a/tests/page/page-event-request.spec.ts +++ b/tests/page/page-event-request.spec.ts @@ -41,6 +41,19 @@ it('should fire for fetches', async ({ page, server }) => { expect(requests.length).toBe(2); }); +it('should fire for fetches with keepalive: true', { + annotation: { + type: 'issue', + description: 'https://github.com/microsoft/playwright/issues/34497' + } +}, async ({ page, server, browserName }) => { + const requests = []; + page.on('request', request => requests.push(request)); + await page.goto(server.EMPTY_PAGE); + await page.evaluate(() => fetch('/empty.html', { keepalive: true })); + expect(requests.length).toBe(2); +}); + it('should report requests and responses handled by service worker', async ({ page, server, isAndroid, isElectron }) => { it.fixme(isAndroid); it.fixme(isElectron); diff --git a/tests/page/page-filechooser.spec.ts b/tests/page/page-filechooser.spec.ts new file mode 100644 index 0000000000000..7fc8cf5500cdf --- /dev/null +++ b/tests/page/page-filechooser.spec.ts @@ -0,0 +1,368 @@ +/** + * Copyright 2017 Google Inc. All rights reserved. + * Modifications copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test, expect } from './pageTest'; +import { attachFrame } from '../config/utils'; + +import fs from 'fs'; +import formidable from 'formidable'; + +test('should upload multiple large files', async ({ page, server, isAndroid, isWebView2, mode }, testInfo) => { + test.skip(isAndroid); + test.skip(isWebView2); + test.skip(mode.startsWith('service')); + test.slow(); + + const filesCount = 10; + await page.goto(server.PREFIX + '/input/fileupload-multi.html'); + const uploadFile = testInfo.outputPath('50MB_1.zip'); + const str = 'A'.repeat(1024); + const stream = fs.createWriteStream(uploadFile); + // 49 is close to the actual limit + for (let i = 0; i < 49 * 1024; i++) { + await new Promise((fulfill, reject) => { + stream.write(str, err => { + if (err) + reject(err); + else + fulfill(); + }); + }); + } + await new Promise(f => stream.end(f)); + const input = page.locator('input[type="file"]'); + const uploadFiles = [uploadFile]; + for (let i = 2; i <= filesCount; i++) { + const dstFile = testInfo.outputPath(`50MB_${i}.zip`); + fs.copyFileSync(uploadFile, dstFile); + uploadFiles.push(dstFile); + } + const fileChooserPromise = page.waitForEvent('filechooser'); + await input.click(); + const fileChooser = await fileChooserPromise; + await fileChooser.setFiles(uploadFiles); + const filesLen = await page.evaluate('document.getElementsByTagName("input")[0].files.length'); + expect(fileChooser.isMultiple()).toBe(true); + expect(filesLen).toEqual(filesCount); + await Promise.all(uploadFiles.map(path => fs.promises.unlink(path))); +}); + +test('should emit event once', async ({ page, server }) => { + await page.setContent(``); + const [chooser] = await Promise.all([ + new Promise(f => page.once('filechooser', f)), + page.click('input'), + ]); + expect(chooser).toBeTruthy(); +}); + +test('should emit event via prepend', async ({ page, server }) => { + await page.setContent(``); + const [chooser] = await Promise.all([ + new Promise(f => page.prependListener('filechooser', f)), + page.click('input'), + ]); + expect(chooser).toBeTruthy(); +}); + +test('should emit event for iframe', async ({ page, server }) => { + const frame = await attachFrame(page, 'frame1', server.EMPTY_PAGE); + await frame.setContent(``); + const [chooser] = await Promise.all([ + new Promise(f => page.once('filechooser', f)), + frame.click('input'), + ]); + expect(chooser).toBeTruthy(); +}); + +test('should emit event on/off', async ({ page, server }) => { + await page.setContent(``); + const [chooser] = await Promise.all([ + new Promise(f => { + const listener = chooser => { + page.off('filechooser', listener); + f(chooser); + }; + page.on('filechooser', listener); + }), + page.click('input'), + ]); + expect(chooser).toBeTruthy(); +}); + +test('should emit event addListener/removeListener', async ({ page, server }) => { + await page.setContent(``); + const [chooser] = await Promise.all([ + new Promise(f => { + const listener = chooser => { + page.removeListener('filechooser', listener); + f(chooser); + }; + page.addListener('filechooser', listener); + }), + page.click('input'), + ]); + expect(chooser).toBeTruthy(); +}); + +test('should work when file input is attached to DOM', async ({ page, server }) => { + await page.setContent(``); + const [chooser] = await Promise.all([ + page.waitForEvent('filechooser'), + page.click('input'), + ]); + expect(chooser).toBeTruthy(); +}); + +test('should work when file input is not attached to DOM', async ({ page, asset }) => { + const [, content] = await Promise.all([ + page.waitForEvent('filechooser').then(chooser => chooser.setFiles(asset('file-to-upload.txt'))), + page.evaluate(async () => { + const el = document.createElement('input'); + el.type = 'file'; + el.click(); + await new Promise(x => el.oninput = x); + const reader = new FileReader(); + const promise = new Promise(fulfill => reader.onload = fulfill); + reader.readAsText(el.files[0]); + return promise.then(() => reader.result); + }), + ]); + expect(content).toBe('contents of the file'); +}); + +test('should not throw when filechooser belongs to iframe', async ({ page, server, browserName }) => { + await page.goto(server.PREFIX + '/frames/one-frame.html'); + const frame = page.mainFrame().childFrames()[0]; + await frame.setContent(` +
Click me
+ + `); + await Promise.all([ + page.waitForEvent('filechooser'), + frame.click('div') + ]); + await page.waitForFunction(() => (window as any).__done); +}); + +test('should not throw when frame is detached immediately', async ({ page, server }) => { + await page.goto(server.PREFIX + '/frames/one-frame.html'); + const frame = page.mainFrame().childFrames()[0]; + await frame.setContent(` +
Click me
+ + `); + page.on('filechooser', () => {}); // To ensure we handle file choosers. + await frame.click('div'); + await page.waitForFunction(() => (window as any).__done); +}); + +test('should respect timeout', async ({ page, playwright }) => { + let error = null; + await page.waitForEvent('filechooser', { timeout: 1 }).catch(e => error = e); + expect(error).toBeInstanceOf(playwright.errors.TimeoutError); +}); + +test('should respect default timeout when there is no custom timeout', async ({ page, playwright }) => { + page.setDefaultTimeout(1); + let error = null; + await page.waitForEvent('filechooser').catch(e => error = e); + expect(error).toBeInstanceOf(playwright.errors.TimeoutError); +}); + +test('should prioritize exact timeout over default timeout', async ({ page, playwright }) => { + page.setDefaultTimeout(0); + let error = null; + await page.waitForEvent('filechooser', { timeout: 1 }).catch(e => error = e); + expect(error).toBeInstanceOf(playwright.errors.TimeoutError); +}); + +test('should work with no timeout', async ({ page, server }) => { + const [chooser] = await Promise.all([ + page.waitForEvent('filechooser', { timeout: 0 }), + page.evaluate(() => window.builtinSetTimeout(() => { + const el = document.createElement('input'); + el.type = 'file'; + el.click(); + }, 50)) + ]); + expect(chooser).toBeTruthy(); +}); + +test('should return the same file chooser when there are many watchdogs simultaneously', async ({ page, server }) => { + await page.setContent(``); + const [fileChooser1, fileChooser2] = await Promise.all([ + page.waitForEvent('filechooser'), + page.waitForEvent('filechooser'), + page.$eval('input', input => input.click()), + ]); + expect(fileChooser1 === fileChooser2).toBe(true); +}); + +test('should accept single file', async ({ page, asset }) => { + await page.setContent(``); + const [fileChooser] = await Promise.all([ + page.waitForEvent('filechooser'), + page.click('input'), + ]); + expect(fileChooser.page()).toBe(page); + expect(fileChooser.element()).toBeTruthy(); + await fileChooser.setFiles(asset('file-to-upload.txt')); + expect(await page.$eval('input', input => input.files.length)).toBe(1); + expect(await page.$eval('input', input => input.files[0].name)).toBe('file-to-upload.txt'); +}); + +// @see https://github.com/microsoft/playwright/issues/4704 +test('should not trim big uploaded files', async ({ page, server }) => { + + let files: Record; + server.setRoute('/upload', async (req, res) => { + const form = new formidable.IncomingForm(); + form.parse(req, function(err, fields, f) { + files = f as Record; + res.end(); + }); + }); + await page.goto(server.EMPTY_PAGE); + + const DATA_SIZE = Math.pow(2, 20); + await Promise.all([ + page.evaluate(async size => { + const body = new FormData(); + body.set('file', new Blob([new Uint8Array(size)])); + await fetch('/upload', { method: 'POST', body }); + }, DATA_SIZE), + server.waitForRequest('/upload'), + ]); + expect(files.file.size).toBe(DATA_SIZE); +}); + +test('should be able to read selected file', async ({ page, asset }) => { + await page.setContent(``); + const [, content] = await Promise.all([ + page.waitForEvent('filechooser').then(fileChooser => fileChooser.setFiles(asset('file-to-upload.txt'))), + page.$eval('input', async picker => { + picker.click(); + await new Promise(x => picker.oninput = x); + const reader = new FileReader(); + const promise = new Promise(fulfill => reader.onload = fulfill); + reader.readAsText(picker.files[0]); + return promise.then(() => reader.result); + }), + ]); + expect(content).toBe('contents of the file'); +}); + +test('should be able to reset selected files with empty file list', async ({ page, asset }) => { + await page.setContent(``); + const [, fileLength1] = await Promise.all([ + page.waitForEvent('filechooser').then(fileChooser => fileChooser.setFiles(asset('file-to-upload.txt'))), + page.$eval('input', async picker => { + picker.click(); + await new Promise(x => picker.oninput = x); + return picker.files.length; + }), + ]); + expect(fileLength1).toBe(1); + const [, fileLength2] = await Promise.all([ + page.waitForEvent('filechooser').then(fileChooser => fileChooser.setFiles([])), + page.$eval('input', async picker => { + picker.click(); + await new Promise(x => picker.oninput = x); + return picker.files.length; + }), + ]); + expect(fileLength2).toBe(0); +}); + +test('should work for single file pick', async ({ page, server }) => { + await page.setContent(``); + const [fileChooser] = await Promise.all([ + page.waitForEvent('filechooser'), + page.click('input'), + ]); + expect(fileChooser.isMultiple()).toBe(false); +}); + +test('should work for "multiple"', async ({ page, server }) => { + await page.setContent(``); + const [fileChooser] = await Promise.all([ + page.waitForEvent('filechooser'), + page.click('input'), + ]); + expect(fileChooser.isMultiple()).toBe(true); +}); + +test('should work for "webkitdirectory"', async ({ page, server }) => { + await page.setContent(``); + const [fileChooser] = await Promise.all([ + page.waitForEvent('filechooser'), + page.click('input'), + ]); + expect(fileChooser.isMultiple()).toBe(true); +}); + +test('should emit event after navigation', async ({ page, server, browserName, browserMajorVersion }) => { + test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/11375' }); + test.skip(browserName === 'chromium' && browserMajorVersion < 99); + + const logs = []; + page.on('filechooser', () => logs.push('filechooser')); + await page.goto(server.PREFIX + '/empty.html'); + await page.setContent(``); + await Promise.all([ + page.waitForEvent('filechooser'), + page.click('input'), + ]); + await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html'); + await page.setContent(``); + await Promise.all([ + page.waitForEvent('filechooser'), + page.click('input'), + ]); + expect(logs).toEqual(['filechooser', 'filechooser']); +}); + +test('should trigger listener added before navigation', async ({ page, server, browserMajorVersion, isElectron }) => { + test.skip(isElectron && browserMajorVersion <= 98); + // Add listener before cross process navigation. + const chooserPromise = new Promise(f => page.once('filechooser', f)); + await page.goto(server.PREFIX + '/empty.html'); + await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html'); + await page.setContent(``); + const [chooser] = await Promise.all([ + chooserPromise, + page.click('input'), + ]); + expect(chooser).toBeTruthy(); +}); diff --git a/tests/page/page-keyboard.spec.ts b/tests/page/page-keyboard.spec.ts index 0d922584f43e1..86ff5508b63e8 100644 --- a/tests/page/page-keyboard.spec.ts +++ b/tests/page/page-keyboard.spec.ts @@ -93,18 +93,18 @@ it('should report shiftKey', async ({ page, server, browserName, platform }) => const codeForKey = { 'Shift': 16, 'Alt': 18, 'Control': 17 }; for (const modifierKey in codeForKey) { await keyboard.down(modifierKey); - expect(await page.evaluate('getResult()')).toBe('Keydown: ' + modifierKey + ' ' + modifierKey + 'Left ' + codeForKey[modifierKey] + ' [' + modifierKey + ']'); + expect(await page.evaluate('getResult()')).toBe('Keydown: ' + modifierKey + ' ' + modifierKey + 'Left LEFT [' + modifierKey + ']'); await keyboard.down('!'); // Shift+! will generate a keypress if (modifierKey === 'Shift') - expect(await page.evaluate('getResult()')).toBe('Keydown: ! Digit1 49 [' + modifierKey + ']\nKeypress: ! Digit1 33 33 [' + modifierKey + ']'); + expect(await page.evaluate('getResult()')).toBe('Keydown: ! Digit1 STANDARD [' + modifierKey + ']\nKeypress: ! Digit1 STANDARD 33 [' + modifierKey + ']'); else - expect(await page.evaluate('getResult()')).toBe('Keydown: ! Digit1 49 [' + modifierKey + ']'); + expect(await page.evaluate('getResult()')).toBe('Keydown: ! Digit1 STANDARD [' + modifierKey + ']'); await keyboard.up('!'); - expect(await page.evaluate('getResult()')).toBe('Keyup: ! Digit1 49 [' + modifierKey + ']'); + expect(await page.evaluate('getResult()')).toBe('Keyup: ! Digit1 STANDARD [' + modifierKey + ']'); await keyboard.up(modifierKey); - expect(await page.evaluate('getResult()')).toBe('Keyup: ' + modifierKey + ' ' + modifierKey + 'Left ' + codeForKey[modifierKey] + ' []'); + expect(await page.evaluate('getResult()')).toBe('Keyup: ' + modifierKey + ' ' + modifierKey + 'Left LEFT []'); } }); @@ -112,31 +112,31 @@ it('should report multiple modifiers', async ({ page, server }) => { await page.goto(server.PREFIX + '/input/keyboard.html'); const keyboard = page.keyboard; await keyboard.down('Control'); - expect(await page.evaluate('getResult()')).toBe('Keydown: Control ControlLeft 17 [Control]'); + expect(await page.evaluate('getResult()')).toBe('Keydown: Control ControlLeft LEFT [Control]'); await keyboard.down('Alt'); - expect(await page.evaluate('getResult()')).toBe('Keydown: Alt AltLeft 18 [Alt Control]'); + expect(await page.evaluate('getResult()')).toBe('Keydown: Alt AltLeft LEFT [Alt Control]'); await keyboard.down(';'); - expect(await page.evaluate('getResult()')).toBe('Keydown: ; Semicolon 186 [Alt Control]'); + expect(await page.evaluate('getResult()')).toBe('Keydown: ; Semicolon STANDARD [Alt Control]'); await keyboard.up(';'); - expect(await page.evaluate('getResult()')).toBe('Keyup: ; Semicolon 186 [Alt Control]'); + expect(await page.evaluate('getResult()')).toBe('Keyup: ; Semicolon STANDARD [Alt Control]'); await keyboard.up('Control'); - expect(await page.evaluate('getResult()')).toBe('Keyup: Control ControlLeft 17 [Alt]'); + expect(await page.evaluate('getResult()')).toBe('Keyup: Control ControlLeft LEFT [Alt]'); await keyboard.up('Alt'); - expect(await page.evaluate('getResult()')).toBe('Keyup: Alt AltLeft 18 []'); + expect(await page.evaluate('getResult()')).toBe('Keyup: Alt AltLeft LEFT []'); }); it('should send proper codes while typing', async ({ page, server }) => { await page.goto(server.PREFIX + '/input/keyboard.html'); await page.keyboard.type('!'); expect(await page.evaluate('getResult()')).toBe( - ['Keydown: ! Digit1 49 []', - 'Keypress: ! Digit1 33 33 []', - 'Keyup: ! Digit1 49 []'].join('\n')); + ['Keydown: ! Digit1 STANDARD []', + 'Keypress: ! Digit1 STANDARD 33 []', + 'Keyup: ! Digit1 STANDARD []'].join('\n')); await page.keyboard.type('^'); expect(await page.evaluate('getResult()')).toBe( - ['Keydown: ^ Digit6 54 []', - 'Keypress: ^ Digit6 94 94 []', - 'Keyup: ^ Digit6 54 []'].join('\n')); + ['Keydown: ^ Digit6 STANDARD []', + 'Keypress: ^ Digit6 STANDARD 94 []', + 'Keyup: ^ Digit6 STANDARD []'].join('\n')); }); it('should send proper codes while typing with shift', async ({ page, server }) => { @@ -145,10 +145,10 @@ it('should send proper codes while typing with shift', async ({ page, server }) await keyboard.down('Shift'); await page.keyboard.type('~'); expect(await page.evaluate('getResult()')).toBe( - ['Keydown: Shift ShiftLeft 16 [Shift]', - 'Keydown: ~ Backquote 192 [Shift]', // 192 is ` keyCode - 'Keypress: ~ Backquote 126 126 [Shift]', // 126 is ~ charCode - 'Keyup: ~ Backquote 192 [Shift]'].join('\n')); + ['Keydown: Shift ShiftLeft LEFT [Shift]', + 'Keydown: ~ Backquote STANDARD [Shift]', + 'Keypress: ~ Backquote STANDARD 126 [Shift]', + 'Keyup: ~ Backquote STANDARD [Shift]'].join('\n')); await keyboard.up('Shift'); }); @@ -173,54 +173,54 @@ it('should press plus', async ({ page, server }) => { await page.goto(server.PREFIX + '/input/keyboard.html'); await page.keyboard.press('+'); expect(await page.evaluate('getResult()')).toBe( - ['Keydown: + Equal 187 []', // 192 is ` keyCode - 'Keypress: + Equal 43 43 []', // 126 is ~ charCode - 'Keyup: + Equal 187 []'].join('\n')); + ['Keydown: + Equal STANDARD []', + 'Keypress: + Equal STANDARD 43 []', + 'Keyup: + Equal STANDARD []'].join('\n')); }); it('should press shift plus', async ({ page, server }) => { await page.goto(server.PREFIX + '/input/keyboard.html'); await page.keyboard.press('Shift++'); expect(await page.evaluate('getResult()')).toBe( - ['Keydown: Shift ShiftLeft 16 [Shift]', - 'Keydown: + Equal 187 [Shift]', // 192 is ` keyCode - 'Keypress: + Equal 43 43 [Shift]', // 126 is ~ charCode - 'Keyup: + Equal 187 [Shift]', - 'Keyup: Shift ShiftLeft 16 []'].join('\n')); + ['Keydown: Shift ShiftLeft LEFT [Shift]', + 'Keydown: + Equal STANDARD [Shift]', + 'Keypress: + Equal STANDARD 43 [Shift]', + 'Keyup: + Equal STANDARD [Shift]', + 'Keyup: Shift ShiftLeft LEFT []'].join('\n')); }); it('should support plus-separated modifiers', async ({ page, server }) => { await page.goto(server.PREFIX + '/input/keyboard.html'); await page.keyboard.press('Shift+~'); expect(await page.evaluate('getResult()')).toBe( - ['Keydown: Shift ShiftLeft 16 [Shift]', - 'Keydown: ~ Backquote 192 [Shift]', // 192 is ` keyCode - 'Keypress: ~ Backquote 126 126 [Shift]', // 126 is ~ charCode - 'Keyup: ~ Backquote 192 [Shift]', - 'Keyup: Shift ShiftLeft 16 []'].join('\n')); + ['Keydown: Shift ShiftLeft LEFT [Shift]', + 'Keydown: ~ Backquote STANDARD [Shift]', + 'Keypress: ~ Backquote STANDARD 126 [Shift]', + 'Keyup: ~ Backquote STANDARD [Shift]', + 'Keyup: Shift ShiftLeft LEFT []'].join('\n')); }); it('should support multiple plus-separated modifiers', async ({ page, server }) => { await page.goto(server.PREFIX + '/input/keyboard.html'); await page.keyboard.press('Control+Shift+~'); expect(await page.evaluate('getResult()')).toBe( - ['Keydown: Control ControlLeft 17 [Control]', - 'Keydown: Shift ShiftLeft 16 [Control Shift]', - 'Keydown: ~ Backquote 192 [Control Shift]', // 192 is ` keyCode - 'Keyup: ~ Backquote 192 [Control Shift]', - 'Keyup: Shift ShiftLeft 16 [Control]', - 'Keyup: Control ControlLeft 17 []'].join('\n')); + ['Keydown: Control ControlLeft LEFT [Control]', + 'Keydown: Shift ShiftLeft LEFT [Control Shift]', + 'Keydown: ~ Backquote STANDARD [Control Shift]', + 'Keyup: ~ Backquote STANDARD [Control Shift]', + 'Keyup: Shift ShiftLeft LEFT [Control]', + 'Keyup: Control ControlLeft LEFT []'].join('\n')); }); it('should shift raw codes', async ({ page, server }) => { await page.goto(server.PREFIX + '/input/keyboard.html'); await page.keyboard.press('Shift+Digit3'); expect(await page.evaluate('getResult()')).toBe( - ['Keydown: Shift ShiftLeft 16 [Shift]', - 'Keydown: # Digit3 51 [Shift]', // 51 is # keyCode - 'Keypress: # Digit3 35 35 [Shift]', // 35 is # charCode - 'Keyup: # Digit3 51 [Shift]', - 'Keyup: Shift ShiftLeft 16 []'].join('\n')); + ['Keydown: Shift ShiftLeft LEFT [Shift]', + 'Keydown: # Digit3 STANDARD [Shift]', + 'Keypress: # Digit3 STANDARD 35 [Shift]', + 'Keyup: # Digit3 STANDARD [Shift]', + 'Keyup: Shift ShiftLeft LEFT []'].join('\n')); }); it('should specify repeat property', async ({ page, server }) => { @@ -710,7 +710,7 @@ it('should have correct Keydown/Keyup order when pressing Escape key', async ({ await page.goto(server.PREFIX + '/input/keyboard.html'); await page.keyboard.press('Escape'); expect(await page.evaluate('getResult()')).toBe(` -Keydown: Escape Escape 27 [] -Keyup: Escape Escape 27 [] +Keydown: Escape Escape STANDARD [] +Keyup: Escape Escape STANDARD [] `.trim()); }); diff --git a/tests/page/page-leaks.spec.ts b/tests/page/page-leaks.spec.ts index abd33e651ecfe..90f78d83a9031 100644 --- a/tests/page/page-leaks.spec.ts +++ b/tests/page/page-leaks.spec.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { MultiMap } from '../../packages/playwright-core/lib/utils/multimap'; +import { MultiMap } from '../../packages/playwright-core/lib/utils/isomorphic/multimap'; import { test, expect } from './pageTest'; function leakedJSHandles(): string { diff --git a/tests/page/page-listeners.spec.ts b/tests/page/page-listeners.spec.ts index c22be6455352e..495ecf36c7f5d 100644 --- a/tests/page/page-listeners.spec.ts +++ b/tests/page/page-listeners.spec.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { ManualPromise } from '../../packages/playwright-core/lib/utils/manualPromise'; +import { ManualPromise } from '../../packages/playwright-core/lib/utils/isomorphic/manualPromise'; import { test as it, expect } from './pageTest'; // This test is mostly for type checking, the actual tests are in the library/events. diff --git a/tests/page/page-set-input-files.spec.ts b/tests/page/page-set-input-files.spec.ts index eaf1316f5cbaf..9129a6ee4f32a 100644 --- a/tests/page/page-set-input-files.spec.ts +++ b/tests/page/page-set-input-files.spec.ts @@ -15,14 +15,13 @@ * limitations under the License. */ -import { test as it, expect } from './pageTest'; -import { attachFrame } from '../config/utils'; +import { test, expect } from './pageTest'; import path from 'path'; import fs from 'fs'; import formidable from 'formidable'; -it('should upload the file', async ({ page, server, asset }) => { +test('should upload the file', async ({ page, server, asset }) => { await page.goto(server.PREFIX + '/input/fileupload.html'); const filePath = path.relative(process.cwd(), asset('file-to-upload.txt')); const input = await page.$('input'); @@ -36,13 +35,13 @@ it('should upload the file', async ({ page, server, asset }) => { }, input)).toBe('contents of the file'); }); -it('should upload a folder', async ({ page, server, browserName, headless, browserMajorVersion, isAndroid, macVersion, isMac }) => { - it.skip(isAndroid); - it.skip(browserName === 'webkit' && isMac && macVersion <= 12, 'WebKit on macOS-12 is frozen'); +test('should upload a folder', async ({ page, server, browserName, headless, browserMajorVersion, isAndroid, macVersion, isMac }) => { + test.skip(isAndroid); + test.skip(browserName === 'webkit' && isMac && macVersion <= 12, 'WebKit on macOS-12 is frozen'); await page.goto(server.PREFIX + '/input/folderupload.html'); const input = await page.$('input'); - const dir = path.join(it.info().outputDir, 'file-upload-test'); + const dir = path.join(test.info().outputDir, 'file-upload-test'); { await fs.promises.mkdir(dir, { recursive: true }); await fs.promises.writeFile(path.join(dir, 'file1.txt'), 'file1 content'); @@ -69,13 +68,13 @@ it('should upload a folder', async ({ page, server, browserName, headless, brows } }); -it('should upload a folder and throw for multiple directories', async ({ page, server, isAndroid, browserName, macVersion, isMac }) => { - it.skip(isAndroid); - it.skip(browserName === 'webkit' && isMac && macVersion <= 12, 'WebKit on macOS-12 is frozen'); +test('should upload a folder and throw for multiple directories', async ({ page, server, isAndroid, browserName, macVersion, isMac }) => { + test.skip(isAndroid); + test.skip(browserName === 'webkit' && isMac && macVersion <= 12, 'WebKit on macOS-12 is frozen'); await page.goto(server.PREFIX + '/input/folderupload.html'); const input = await page.$('input'); - const dir = path.join(it.info().outputDir, 'file-upload-test'); + const dir = path.join(test.info().outputDir, 'file-upload-test'); { await fs.promises.mkdir(path.join(dir, 'folder1'), { recursive: true }); await fs.promises.writeFile(path.join(dir, 'folder1', 'file1.txt'), 'file1 content'); @@ -88,13 +87,13 @@ it('should upload a folder and throw for multiple directories', async ({ page, s ])).rejects.toThrow('Multiple directories are not supported'); }); -it('should throw if a directory and files are passed', async ({ page, server, isAndroid, browserName, macVersion, isMac }) => { - it.skip(isAndroid); - it.skip(browserName === 'webkit' && isMac && macVersion <= 12, 'WebKit on macOS-12 is frozen'); +test('should throw if a directory and files are passed', async ({ page, server, isAndroid, browserName, macVersion, isMac }) => { + test.skip(isAndroid); + test.skip(browserName === 'webkit' && isMac && macVersion <= 12, 'WebKit on macOS-12 is frozen'); await page.goto(server.PREFIX + '/input/folderupload.html'); const input = await page.$('input'); - const dir = path.join(it.info().outputDir, 'file-upload-test'); + const dir = path.join(test.info().outputDir, 'file-upload-test'); { await fs.promises.mkdir(path.join(dir, 'folder1'), { recursive: true }); await fs.promises.writeFile(path.join(dir, 'folder1', 'file1.txt'), 'file1 content'); @@ -105,13 +104,13 @@ it('should throw if a directory and files are passed', async ({ page, server, is ])).rejects.toThrow('File paths must be all files or a single directory'); }); -it('should throw when uploading a folder in a normal file upload input', async ({ page, server, isAndroid, browserName, macVersion, isMac }) => { - it.skip(isAndroid); - it.skip(browserName === 'webkit' && isMac && macVersion <= 12, 'WebKit on macOS-12 is frozen'); +test('should throw when uploading a folder in a normal file upload input', async ({ page, server, isAndroid, browserName, macVersion, isMac }) => { + test.skip(isAndroid); + test.skip(browserName === 'webkit' && isMac && macVersion <= 12, 'WebKit on macOS-12 is frozen'); await page.goto(server.PREFIX + '/input/fileupload.html'); const input = await page.$('input'); - const dir = path.join(it.info().outputDir, 'file-upload-test'); + const dir = path.join(test.info().outputDir, 'file-upload-test'); { await fs.promises.mkdir(path.join(dir), { recursive: true }); await fs.promises.writeFile(path.join(dir, 'file1.txt'), 'file1 content'); @@ -119,17 +118,17 @@ it('should throw when uploading a folder in a normal file upload input', async ( await expect(input.setInputFiles(dir)).rejects.toThrow('File input does not support directories, pass individual files instead'); }); -it('should throw when uploading a file in a directory upload input', async ({ page, server, isAndroid, asset, browserName, macVersion, isMac }) => { - it.skip(isAndroid); - it.skip(browserName === 'webkit' && isMac && macVersion <= 12, 'WebKit on macOS-12 is frozen'); +test('should throw when uploading a file in a directory upload input', async ({ page, server, isAndroid, asset, browserName, macVersion, isMac }) => { + test.skip(isAndroid); + test.skip(browserName === 'webkit' && isMac && macVersion <= 12, 'WebKit on macOS-12 is frozen'); await page.goto(server.PREFIX + '/input/folderupload.html'); const input = await page.$('input'); await expect(input.setInputFiles(asset('file to upload.txt'))).rejects.toThrow('[webkitdirectory] input requires passing a path to a directory'); }); -it('should upload a file after popup', async ({ page, server, asset }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/29923' }); +test('should upload a file after popup', async ({ page, server, asset }) => { + test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/29923' }); await page.goto(server.PREFIX + '/input/fileupload.html'); { const [popup] = await Promise.all([ @@ -144,11 +143,11 @@ it('should upload a file after popup', async ({ page, server, asset }) => { expect(await page.evaluate(e => e.files[0].name, input)).toBe('file-to-upload.txt'); }); -it('should upload large file', async ({ page, server, isAndroid, isWebView2, mode }, testInfo) => { - it.skip(isAndroid); - it.skip(isWebView2); - it.skip(mode.startsWith('service')); - it.slow(); +test('should upload large file', async ({ page, server, isAndroid, isWebView2, mode }, testInfo) => { + test.skip(isAndroid); + test.skip(isWebView2); + test.skip(mode.startsWith('service')); + test.slow(); await page.goto(server.PREFIX + '/input/fileupload.html'); const uploadFile = testInfo.outputPath('200MB.zip'); @@ -194,7 +193,7 @@ it('should upload large file', async ({ page, server, isAndroid, isWebView2, mod await Promise.all([uploadFile, file1.filepath].map(fs.promises.unlink)); }); -it('should throw an error if the file does not exist', async ({ page, server, asset }) => { +test('should throw an error if the file does not exist', async ({ page, server, asset }) => { await page.goto(server.PREFIX + '/input/fileupload.html'); const input = await page.$('input'); const error = await input.setInputFiles('i actually do not exist.txt').catch(e => e); @@ -202,51 +201,11 @@ it('should throw an error if the file does not exist', async ({ page, server, as expect(error.message).toContain('i actually do not exist.txt'); }); -it('should upload multiple large files', async ({ page, server, isAndroid, isWebView2, mode }, testInfo) => { - it.skip(isAndroid); - it.skip(isWebView2); - it.skip(mode.startsWith('service')); - it.slow(); - - const filesCount = 10; - await page.goto(server.PREFIX + '/input/fileupload-multi.html'); - const uploadFile = testInfo.outputPath('50MB_1.zip'); - const str = 'A'.repeat(1024); - const stream = fs.createWriteStream(uploadFile); - // 49 is close to the actual limit - for (let i = 0; i < 49 * 1024; i++) { - await new Promise((fulfill, reject) => { - stream.write(str, err => { - if (err) - reject(err); - else - fulfill(); - }); - }); - } - await new Promise(f => stream.end(f)); - const input = page.locator('input[type="file"]'); - const uploadFiles = [uploadFile]; - for (let i = 2; i <= filesCount; i++) { - const dstFile = testInfo.outputPath(`50MB_${i}.zip`); - fs.copyFileSync(uploadFile, dstFile); - uploadFiles.push(dstFile); - } - const fileChooserPromise = page.waitForEvent('filechooser'); - await input.click(); - const fileChooser = await fileChooserPromise; - await fileChooser.setFiles(uploadFiles); - const filesLen = await page.evaluate('document.getElementsByTagName("input")[0].files.length'); - expect(fileChooser.isMultiple()).toBe(true); - expect(filesLen).toEqual(filesCount); - await Promise.all(uploadFiles.map(path => fs.promises.unlink(path))); -}); - -it('should upload large file with relative path', async ({ page, server, isAndroid, isWebView2, mode }, testInfo) => { - it.skip(isAndroid); - it.skip(isWebView2); - it.skip(mode.startsWith('service')); - it.slow(); +test('should upload large file with relative path', async ({ page, server, isAndroid, isWebView2, mode }, testInfo) => { + test.skip(isAndroid); + test.skip(isWebView2); + test.skip(mode.startsWith('service')); + test.slow(); await page.goto(server.PREFIX + '/input/fileupload.html'); const uploadFile = testInfo.outputPath('200MB.zip'); @@ -294,8 +253,8 @@ it('should upload large file with relative path', async ({ page, server, isAndro await Promise.all([uploadFile, file1.filepath].map(fs.promises.unlink)); }); -it('should upload the file with spaces in name', async ({ page, server, asset }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/17451' }); +test('should upload the file with spaces in name', async ({ page, server, asset }) => { + test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/17451' }); await page.goto(server.PREFIX + '/input/fileupload.html'); const filePath = path.relative(process.cwd(), asset('file to upload.txt')); const input = await page.$('input'); @@ -310,14 +269,14 @@ it('should upload the file with spaces in name', async ({ page, server, asset }) }); -it('should work @smoke', async ({ page, asset }) => { +test('should work @smoke', async ({ page, asset }) => { await page.setContent(``); await page.setInputFiles('input', asset('file-to-upload.txt')); expect(await page.$eval('input', input => input.files.length)).toBe(1); expect(await page.$eval('input', input => input.files[0].name)).toBe('file-to-upload.txt'); }); -it('should set from memory', async ({ page }) => { +test('should set from memory', async ({ page }) => { await page.setContent(``); await page.setInputFiles('input', { name: 'test.txt', @@ -328,133 +287,7 @@ it('should set from memory', async ({ page }) => { expect(await page.$eval('input', input => input.files[0].name)).toBe('test.txt'); }); -it('should emit event once', async ({ page, server }) => { - await page.setContent(``); - const [chooser] = await Promise.all([ - new Promise(f => page.once('filechooser', f)), - page.click('input'), - ]); - expect(chooser).toBeTruthy(); -}); - -it('should emit event via prepend', async ({ page, server }) => { - await page.setContent(``); - const [chooser] = await Promise.all([ - new Promise(f => page.prependListener('filechooser', f)), - page.click('input'), - ]); - expect(chooser).toBeTruthy(); -}); - -it('should emit event for iframe', async ({ page, server }) => { - const frame = await attachFrame(page, 'frame1', server.EMPTY_PAGE); - await frame.setContent(``); - const [chooser] = await Promise.all([ - new Promise(f => page.once('filechooser', f)), - frame.click('input'), - ]); - expect(chooser).toBeTruthy(); -}); - -it('should emit event on/off', async ({ page, server }) => { - await page.setContent(``); - const [chooser] = await Promise.all([ - new Promise(f => { - const listener = chooser => { - page.off('filechooser', listener); - f(chooser); - }; - page.on('filechooser', listener); - }), - page.click('input'), - ]); - expect(chooser).toBeTruthy(); -}); - -it('should emit event addListener/removeListener', async ({ page, server }) => { - await page.setContent(``); - const [chooser] = await Promise.all([ - new Promise(f => { - const listener = chooser => { - page.removeListener('filechooser', listener); - f(chooser); - }; - page.addListener('filechooser', listener); - }), - page.click('input'), - ]); - expect(chooser).toBeTruthy(); -}); - -it('should work when file input is attached to DOM', async ({ page, server }) => { - await page.setContent(``); - const [chooser] = await Promise.all([ - page.waitForEvent('filechooser'), - page.click('input'), - ]); - expect(chooser).toBeTruthy(); -}); - -it('should work when file input is not attached to DOM', async ({ page, asset }) => { - const [, content] = await Promise.all([ - page.waitForEvent('filechooser').then(chooser => chooser.setFiles(asset('file-to-upload.txt'))), - page.evaluate(async () => { - const el = document.createElement('input'); - el.type = 'file'; - el.click(); - await new Promise(x => el.oninput = x); - const reader = new FileReader(); - const promise = new Promise(fulfill => reader.onload = fulfill); - reader.readAsText(el.files[0]); - return promise.then(() => reader.result); - }), - ]); - expect(content).toBe('contents of the file'); -}); - -it('should not throw when filechooser belongs to iframe', async ({ page, server, browserName }) => { - await page.goto(server.PREFIX + '/frames/one-frame.html'); - const frame = page.mainFrame().childFrames()[0]; - await frame.setContent(` -
Click me
- - `); - await Promise.all([ - page.waitForEvent('filechooser'), - frame.click('div') - ]); - await page.waitForFunction(() => (window as any).__done); -}); - -it('should not throw when frame is detached immediately', async ({ page, server }) => { - await page.goto(server.PREFIX + '/frames/one-frame.html'); - const frame = page.mainFrame().childFrames()[0]; - await frame.setContent(` -
Click me
- - `); - page.on('filechooser', () => {}); // To ensure we handle file choosers. - await frame.click('div'); - await page.waitForFunction(() => (window as any).__done); -}); - -it('should work with CSP', async ({ page, server, asset }) => { +test('should work with CSP', async ({ page, server, asset }) => { server.setCSP('/empty.html', 'default-src "none"'); await page.goto(server.EMPTY_PAGE); await page.setContent(``); @@ -463,62 +296,7 @@ it('should work with CSP', async ({ page, server, asset }) => { expect(await page.$eval('input', input => input.files[0].name)).toBe('file-to-upload.txt'); }); -it('should respect timeout', async ({ page, playwright }) => { - let error = null; - await page.waitForEvent('filechooser', { timeout: 1 }).catch(e => error = e); - expect(error).toBeInstanceOf(playwright.errors.TimeoutError); -}); - -it('should respect default timeout when there is no custom timeout', async ({ page, playwright }) => { - page.setDefaultTimeout(1); - let error = null; - await page.waitForEvent('filechooser').catch(e => error = e); - expect(error).toBeInstanceOf(playwright.errors.TimeoutError); -}); - -it('should prioritize exact timeout over default timeout', async ({ page, playwright }) => { - page.setDefaultTimeout(0); - let error = null; - await page.waitForEvent('filechooser', { timeout: 1 }).catch(e => error = e); - expect(error).toBeInstanceOf(playwright.errors.TimeoutError); -}); - -it('should work with no timeout', async ({ page, server }) => { - const [chooser] = await Promise.all([ - page.waitForEvent('filechooser', { timeout: 0 }), - page.evaluate(() => window.builtinSetTimeout(() => { - const el = document.createElement('input'); - el.type = 'file'; - el.click(); - }, 50)) - ]); - expect(chooser).toBeTruthy(); -}); - -it('should return the same file chooser when there are many watchdogs simultaneously', async ({ page, server }) => { - await page.setContent(``); - const [fileChooser1, fileChooser2] = await Promise.all([ - page.waitForEvent('filechooser'), - page.waitForEvent('filechooser'), - page.$eval('input', input => input.click()), - ]); - expect(fileChooser1 === fileChooser2).toBe(true); -}); - -it('should accept single file', async ({ page, asset }) => { - await page.setContent(``); - const [fileChooser] = await Promise.all([ - page.waitForEvent('filechooser'), - page.click('input'), - ]); - expect(fileChooser.page()).toBe(page); - expect(fileChooser.element()).toBeTruthy(); - await fileChooser.setFiles(asset('file-to-upload.txt')); - expect(await page.$eval('input', input => input.files.length)).toBe(1); - expect(await page.$eval('input', input => input.files[0].name)).toBe('file-to-upload.txt'); -}); - -it('should detect mime type', async ({ page, server, asset }) => { +test('should detect mime type', async ({ page, server, asset }) => { let files: Record; server.setRoute('/upload', async (req, res) => { @@ -553,7 +331,7 @@ it('should detect mime type', async ({ page, server, asset }) => { }); // @see https://github.com/microsoft/playwright/issues/4704 -it('should not trim big uploaded files', async ({ page, server }) => { +test('should not trim big uploaded files', async ({ page, server }) => { let files: Record; server.setRoute('/upload', async (req, res) => { @@ -577,59 +355,7 @@ it('should not trim big uploaded files', async ({ page, server }) => { expect(files.file.size).toBe(DATA_SIZE); }); -it('should be able to read selected file', async ({ page, asset }) => { - await page.setContent(``); - const [, content] = await Promise.all([ - page.waitForEvent('filechooser').then(fileChooser => fileChooser.setFiles(asset('file-to-upload.txt'))), - page.$eval('input', async picker => { - picker.click(); - await new Promise(x => picker.oninput = x); - const reader = new FileReader(); - const promise = new Promise(fulfill => reader.onload = fulfill); - reader.readAsText(picker.files[0]); - return promise.then(() => reader.result); - }), - ]); - expect(content).toBe('contents of the file'); -}); - -it('should be able to reset selected files with empty file list', async ({ page, asset }) => { - await page.setContent(``); - const [, fileLength1] = await Promise.all([ - page.waitForEvent('filechooser').then(fileChooser => fileChooser.setFiles(asset('file-to-upload.txt'))), - page.$eval('input', async picker => { - picker.click(); - await new Promise(x => picker.oninput = x); - return picker.files.length; - }), - ]); - expect(fileLength1).toBe(1); - const [, fileLength2] = await Promise.all([ - page.waitForEvent('filechooser').then(fileChooser => fileChooser.setFiles([])), - page.$eval('input', async picker => { - picker.click(); - await new Promise(x => picker.oninput = x); - return picker.files.length; - }), - ]); - expect(fileLength2).toBe(0); -}); - -it('should not accept multiple files for single-file input', async ({ page, asset }) => { - await page.setContent(``); - const [fileChooser] = await Promise.all([ - page.waitForEvent('filechooser'), - page.click('input'), - ]); - let error = null; - await fileChooser.setFiles([ - asset('file-to-upload.txt'), - asset('pptr.png') - ]).catch(e => error = e); - expect(error).not.toBe(null); -}); - -it('should emit input and change events', async ({ page, asset }) => { +test('should emit input and change events', async ({ page, asset }) => { const events = []; await page.exposeFunction('eventHandled', e => events.push(e)); await page.setContent(` @@ -644,8 +370,8 @@ it('should emit input and change events', async ({ page, asset }) => { expect(events[1].type).toBe('change'); }); -it('input event.composed should be true and cross shadow dom boundary', async ({ page, server, asset }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/28726' }); +test('input event.composed should be true and cross shadow dom boundary', async ({ page, server, asset }) => { + test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/28726' }); await page.goto(server.EMPTY_PAGE); await page.setContent(`