diff --git a/.github/workflows/compiler_typescript.yml b/.github/workflows/compiler_typescript.yml index 95f8f1f26e112..65fb789eccf17 100644 --- a/.github/workflows/compiler_typescript.yml +++ b/.github/workflows/compiler_typescript.yml @@ -75,8 +75,8 @@ jobs: name: Test ${{ matrix.workspace_name }} needs: discover_yarn_workspaces runs-on: ubuntu-latest - continue-on-error: true strategy: + fail-fast: false matrix: workspace_name: ${{ fromJSON(needs.discover_yarn_workspaces.outputs.matrix) }} steps: @@ -93,4 +93,7 @@ jobs: path: "**/node_modules" key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }} - run: yarn install --frozen-lockfile + - run: xvfb-run -a yarn workspace ${{ matrix.workspace_name }} test + if: runner.os == 'Linux' && matrix.workspace_name == 'react-forgive' - run: yarn workspace ${{ matrix.workspace_name }} test + if: runner.os != 'Linux' && matrix.workspace_name != 'react-forgive' diff --git a/.github/workflows/devtools_regression_tests.yml b/.github/workflows/devtools_regression_tests.yml index 64d6707aa3688..4babfeefb0f2c 100644 --- a/.github/workflows/devtools_regression_tests.yml +++ b/.github/workflows/devtools_regression_tests.yml @@ -100,6 +100,7 @@ jobs: needs: build_devtools_and_process_artifacts runs-on: ubuntu-latest strategy: + fail-fast: false matrix: version: - "16.0" @@ -108,7 +109,6 @@ jobs: - "17.0" - "18.0" - "18.2" # compiler polyfill - continue-on-error: true steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -135,6 +135,7 @@ jobs: needs: build_devtools_and_process_artifacts runs-on: ubuntu-latest strategy: + fail-fast: false matrix: version: - "16.0" @@ -142,7 +143,6 @@ jobs: - "16.8" # hooks - "17.0" - "18.0" - continue-on-error: true steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 diff --git a/.github/workflows/runtime_build_and_test.yml b/.github/workflows/runtime_build_and_test.yml index 12e341a86fd96..d53e352fbb266 100644 --- a/.github/workflows/runtime_build_and_test.yml +++ b/.github/workflows/runtime_build_and_test.yml @@ -38,8 +38,8 @@ jobs: name: Flow check ${{ matrix.flow_inline_config_shortname }} needs: discover_flow_inline_configs runs-on: ubuntu-latest - continue-on-error: true strategy: + fail-fast: false matrix: flow_inline_config_shortname: ${{ fromJSON(needs.discover_flow_inline_configs.outputs.matrix) }} steps: @@ -117,6 +117,7 @@ jobs: name: yarn test ${{ matrix.params }} (Shard ${{ matrix.shard }}) runs-on: ubuntu-latest strategy: + fail-fast: false matrix: params: - "-r=stable --env=development" @@ -144,7 +145,6 @@ jobs: - 3/5 - 4/5 - 5/5 - continue-on-error: true steps: - uses: actions/checkout@v4 with: @@ -170,6 +170,7 @@ jobs: name: yarn build and lint runs-on: ubuntu-latest strategy: + fail-fast: false matrix: # yml is dumb. update the --total arg to yarn build if you change the number of workers worker_id: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19] @@ -215,6 +216,7 @@ jobs: name: yarn test-build needs: build_and_lint strategy: + fail-fast: false matrix: test_params: [ # Intentionally passing these as strings instead of creating a @@ -250,7 +252,6 @@ jobs: - 1/3 - 2/3 - 3/3 - continue-on-error: true runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -500,6 +501,7 @@ jobs: needs: build_and_lint runs-on: ubuntu-latest strategy: + fail-fast: false matrix: browser: [chrome, firefox, edge] steps: diff --git a/.github/workflows/runtime_eslint_plugin_e2e.yml b/.github/workflows/runtime_eslint_plugin_e2e.yml index edc188f38622e..f8878548c0597 100644 --- a/.github/workflows/runtime_eslint_plugin_e2e.yml +++ b/.github/workflows/runtime_eslint_plugin_e2e.yml @@ -20,13 +20,13 @@ jobs: name: ESLint v${{ matrix.eslint_major }} runs-on: ubuntu-latest strategy: + fail-fast: false matrix: eslint_major: - "6" - "7" - "8" - "9" - continue-on-error: true steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/runtime_releases_from_npm_manual.yml b/.github/workflows/runtime_releases_from_npm_manual.yml new file mode 100644 index 0000000000000..c0b3867e03da0 --- /dev/null +++ b/.github/workflows/runtime_releases_from_npm_manual.yml @@ -0,0 +1,125 @@ +name: (Runtime) Publish Releases from NPM Manual + +on: + workflow_dispatch: + inputs: + version_to_promote: + required: true + description: Current npm version (non-experimental) to promote + type: string + version_to_publish: + required: true + description: Version to publish for the specified packages + type: string + only_packages: + description: Packages to publish (space separated) + type: string + skip_packages: + description: Packages to NOT publish (space separated) + type: string + tags: + description: NPM tags (space separated) + type: string + default: untagged + dry: + required: true + description: Dry run instead of publish? + type: boolean + default: true + force_notify: + description: Force a Discord notification? + type: boolean + default: false + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + GH_TOKEN: ${{ github.token }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + +jobs: + notify: + if: ${{ inputs.force_notify || inputs.dry == false || inputs.dry == 'false' }} + runs-on: ubuntu-latest + steps: + - name: Discord Webhook Action + uses: tsickert/discord-webhook@v6.0.0 + with: + webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} + embed-author-name: ${{ github.event.sender.login }} + embed-author-url: ${{ github.event.sender.html_url }} + embed-author-icon-url: ${{ github.event.sender.avatar_url }} + embed-title: "⚠️ Publishing release from NPM${{ (inputs.dry && ' (dry run)') || '' }}" + embed-description: | + ```json + ${{ toJson(inputs) }} + ``` + embed-url: https://github.com/facebook/react/actions/runs/${{ github.run_id }} + + publish: + name: Publish releases + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: yarn + cache-dependency-path: yarn.lock + - name: Restore cached node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: "**/node_modules" + key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + - run: yarn install --frozen-lockfile + working-directory: scripts/release + - run: cp ./scripts/release/ci-npmrc ~/.npmrc + - if: '${{ inputs.only_packages }}' + name: 'Prepare ${{ inputs.only_packages }} from NPM' + run: | + scripts/release/prepare-release-from-npm.js \ + --ci \ + --skipTests \ + --version=${{ inputs.version_to_promote }} \ + --publishVersion=${{ inputs.version_to_publish }} \ + --onlyPackages=${{ inputs.only_packages }} + - if: '${{ inputs.skip_packages }}' + name: 'Prepare all packages EXCEPT ${{ inputs.skip_packages }} from NPM' + run: | + scripts/release/prepare-release-from-npm.js \ + --ci \ + --skipTests \ + --version=${{ inputs.version_to_promote }} \ + --publishVersion=${{ inputs.version_to_publish }} \ + --skipPackages=${{ inputs.skip_packages }} + - name: Check prepared files + run: ls -R build/node_modules + - if: '${{ inputs.only_packages }}' + name: 'Publish ${{ inputs.only_packages }}' + run: | + scripts/release/publish.js \ + --ci \ + --tags=${{ inputs.tags }} \ + --publishVersion=${{ inputs.version_to_publish }} \ + --onlyPackages=${{ inputs.only_packages }} ${{ (inputs.dry && '') || '\'}} + ${{ inputs.dry && '--dry'}} + - if: '${{ inputs.skip_packages }}' + name: 'Publish all packages EXCEPT ${{ inputs.skip_packages }}' + run: | + scripts/release/publish.js \ + --ci \ + --tags=${{ inputs.tags }} \ + --publishVersion=${{ inputs.version_to_publish }} \ + --skipPackages=${{ inputs.skip_packages }} ${{ (inputs.dry && '') || '\'}} + ${{ inputs.dry && '--dry'}} + - name: Archive released package for debugging + uses: actions/upload-artifact@v4 + with: + name: build + path: | + ./build/node_modules diff --git a/.gitignore b/.gitignore index 2a20fc2427c98..6432df4f054d8 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ packages/react-devtools-fusebox/dist packages/react-devtools-inline/dist packages/react-devtools-shell/dist packages/react-devtools-timeline/dist + diff --git a/compiler/.gitignore b/compiler/.gitignore index 01003c659c622..d41f59333aa09 100644 --- a/compiler/.gitignore +++ b/compiler/.gitignore @@ -21,4 +21,8 @@ dist .spr.yml testfilter.txt -bundle-oss.sh \ No newline at end of file +bundle-oss.sh + +# forgive +*.vsix +.vscode-test diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts index 35c2c4134eb44..781abd05f35da 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts @@ -176,41 +176,48 @@ export type CompilationMode = z.infer; * babel or other unhandled exceptions). */ export type LoggerEvent = - | { - kind: 'CompileError'; - fnLoc: t.SourceLocation | null; - detail: CompilerErrorDetailOptions; - } - | { - kind: 'CompileDiagnostic'; - fnLoc: t.SourceLocation | null; - detail: Omit, 'suggestions'>; - } - | { - kind: 'CompileSkip'; - fnLoc: t.SourceLocation | null; - reason: string; - loc: t.SourceLocation | null; - } - | { - kind: 'CompileSuccess'; - fnLoc: t.SourceLocation | null; - fnName: string | null; - memoSlots: number; - memoBlocks: number; - memoValues: number; - prunedMemoBlocks: number; - prunedMemoValues: number; - } - | { - kind: 'PipelineError'; - fnLoc: t.SourceLocation | null; - data: string; - } - | { - kind: 'Timing'; - measurement: PerformanceMeasure; - }; + | CompileSuccessEvent + | CompileErrorEvent + | CompileDiagnosticEvent + | CompileSkipEvent + | PipelineErrorEvent + | TimingEvent; + +export type CompileErrorEvent = { + kind: 'CompileError'; + fnLoc: t.SourceLocation | null; + detail: CompilerErrorDetailOptions; +}; +export type CompileDiagnosticEvent = { + kind: 'CompileDiagnostic'; + fnLoc: t.SourceLocation | null; + detail: Omit, 'suggestions'>; +}; +export type CompileSuccessEvent = { + kind: 'CompileSuccess'; + fnLoc: t.SourceLocation | null; + fnName: string | null; + memoSlots: number; + memoBlocks: number; + memoValues: number; + prunedMemoBlocks: number; + prunedMemoValues: number; +}; +export type CompileSkipEvent = { + kind: 'CompileSkip'; + fnLoc: t.SourceLocation | null; + reason: string; + loc: t.SourceLocation | null; +}; +export type PipelineErrorEvent = { + kind: 'PipelineError'; + fnLoc: t.SourceLocation | null; + data: string; +}; +export type TimingEvent = { + kind: 'Timing'; + measurement: PerformanceMeasure; +}; export type Logger = { logEvent: (filename: string | null, event: LoggerEvent) => void; diff --git a/compiler/packages/react-forgive/.vscode-test.mjs b/compiler/packages/react-forgive/.vscode-test.mjs new file mode 100644 index 0000000000000..738bfc71b9ced --- /dev/null +++ b/compiler/packages/react-forgive/.vscode-test.mjs @@ -0,0 +1,3 @@ +import {defineConfig} from '@vscode/test-cli'; + +export default defineConfig({files: 'dist/test/**/*.test.js'}); diff --git a/compiler/packages/react-forgive/.vscodeignore b/compiler/packages/react-forgive/.vscodeignore new file mode 100644 index 0000000000000..9ef76302ed597 --- /dev/null +++ b/compiler/packages/react-forgive/.vscodeignore @@ -0,0 +1,5 @@ +**/node_modules +client +server +scripts +.vscode-test.mjs diff --git a/compiler/packages/react-forgive/.yarnrc b/compiler/packages/react-forgive/.yarnrc new file mode 100644 index 0000000000000..123ac74a0a3de --- /dev/null +++ b/compiler/packages/react-forgive/.yarnrc @@ -0,0 +1 @@ +ignore-engines true diff --git a/compiler/packages/react-forgive/LICENSE b/compiler/packages/react-forgive/LICENSE new file mode 100644 index 0000000000000..b93be90515ccd --- /dev/null +++ b/compiler/packages/react-forgive/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Meta Platforms, Inc. and affiliates. + +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. diff --git a/compiler/packages/react-forgive/client/package.json b/compiler/packages/react-forgive/client/package.json new file mode 100644 index 0000000000000..a975439726f23 --- /dev/null +++ b/compiler/packages/react-forgive/client/package.json @@ -0,0 +1,22 @@ +{ + "private": "true", + "name": "react-forgive-client", + "version": "0.0.0", + "description": "Experimental LSP client", + "license": "MIT", + "scripts": { + "build": "echo 'no build'", + "test": "echo 'no tests'" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/facebook/react.git", + "directory": "compiler/packages/react-forgive" + }, + "dependencies": { + "vscode-languageclient": "^9.0.1" + }, + "devDependencies": { + "@types/vscode": "^1.95.0" + } +} diff --git a/compiler/packages/react-forgive/client/src/extension.ts b/compiler/packages/react-forgive/client/src/extension.ts new file mode 100644 index 0000000000000..402f298fd74c5 --- /dev/null +++ b/compiler/packages/react-forgive/client/src/extension.ts @@ -0,0 +1,60 @@ +import * as path from 'path'; +import {ExtensionContext, window as Window} from 'vscode'; + +import { + LanguageClient, + LanguageClientOptions, + ServerOptions, + TransportKind, +} from 'vscode-languageclient/node'; + +let client: LanguageClient; + +export function activate(context: ExtensionContext) { + const serverModule = context.asAbsolutePath(path.join('dist', 'server.js')); + + // If the extension is launched in debug mode then the debug server options are used + // Otherwise the run options are used + const serverOptions: ServerOptions = { + run: { + module: serverModule, + transport: TransportKind.ipc, + }, + debug: { + module: serverModule, + transport: TransportKind.ipc, + }, + }; + + const clientOptions: LanguageClientOptions = { + documentSelector: [ + {scheme: 'file', language: 'javascriptreact'}, + {scheme: 'file', language: 'typescriptreact'}, + ], + progressOnInitialization: true, + }; + + // Create the language client and start the client. + try { + client = new LanguageClient( + 'react-forgive', + 'React Analyzer', + serverOptions, + clientOptions, + ); + } catch { + Window.showErrorMessage( + `React Analyzer couldn't be started. See the output channel for details.`, + ); + return; + } + + client.registerProposedFeatures(); + client.start(); +} + +export function deactivate(): Thenable | undefined { + if (client !== undefined) { + return client.stop(); + } +} diff --git a/compiler/packages/react-forgive/client/yarn.lock b/compiler/packages/react-forgive/client/yarn.lock new file mode 100644 index 0000000000000..b96751788c77b --- /dev/null +++ b/compiler/packages/react-forgive/client/yarn.lock @@ -0,0 +1,59 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/vscode@^1.95.0": + version "1.96.0" + resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.96.0.tgz#3181004bf25d71677ae4aacdd7605a3fd7edf08e" + integrity sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +minimatch@^5.1.0: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +semver@^7.3.7: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +vscode-jsonrpc@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz#f43dfa35fb51e763d17cd94dcca0c9458f35abf9" + integrity sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA== + +vscode-languageclient@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz#cdfe20267726c8d4db839dc1e9d1816e1296e854" + integrity sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA== + dependencies: + minimatch "^5.1.0" + semver "^7.3.7" + vscode-languageserver-protocol "3.17.5" + +vscode-languageserver-protocol@3.17.5: + version "3.17.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz#864a8b8f390835572f4e13bd9f8313d0e3ac4bea" + integrity sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg== + dependencies: + vscode-jsonrpc "8.2.0" + vscode-languageserver-types "3.17.5" + +vscode-languageserver-types@3.17.5: + version "3.17.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz#3273676f0cf2eab40b3f44d085acbb7f08a39d8a" + integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg== diff --git a/compiler/packages/react-forgive/package.json b/compiler/packages/react-forgive/package.json new file mode 100644 index 0000000000000..0bf48e232ecf4 --- /dev/null +++ b/compiler/packages/react-forgive/package.json @@ -0,0 +1,62 @@ +{ + "name": "react-forgive", + "displayName": "React Analyzer", + "description": "React LSP", + "license": "MIT", + "version": "0.0.0", + "repository": { + "type": "git", + "url": "git+https://github.com/facebook/react.git", + "directory": "compiler/packages/react-forgive" + }, + "categories": [ + "Programming Languages" + ], + "keywords": [ + "react", + "react analyzer", + "react compiler" + ], + "publisher": "Meta", + "engines": { + "vscode": "^1.96.0" + }, + "activationEvents": [ + "onLanguage:javascriptreact", + "onLanguage:typescriptreact" + ], + "main": "./dist/extension.js", + "contributes": { + "commands": [ + { + "command": "react-forgive.toggleAll", + "title": "React Analyzer: Toggle on/off" + } + ] + }, + "scripts": { + "build": "yarn run compile", + "compile": "rimraf dist && concurrently -n server,client \"scripts/build.mjs -t server\" \"scripts/build.mjs -t client\"", + "dev": "yarn run package && yarn run install-ext", + "install-ext": "code --install-extension react-forgive-0.0.0.vsix", + "lint": "echo 'no tests'", + "package": "rm -f react-forgive-0.0.0.vsix && vsce package --yarn", + "postinstall": "cd client && yarn install && cd ../server && yarn install && cd ..", + "pretest": "yarn run compile && yarn run lint", + "test": "vscode-test", + "vscode:prepublish": "yarn run compile", + "watch": "scripts/build.mjs --watch" + }, + "devDependencies": { + "@eslint/js": "^9.13.0", + "@types/mocha": "^10.0.10", + "@types/node": "^20", + "@types/vscode": "^1.96.0", + "@vscode/test-cli": "^0.0.10", + "@vscode/test-electron": "^2.4.1", + "eslint": "^9.13.0", + "mocha": "^11.0.1", + "typescript-eslint": "^8.16.0", + "yargs": "^17.7.2" + } +} diff --git a/compiler/packages/react-forgive/scripts/build.mjs b/compiler/packages/react-forgive/scripts/build.mjs new file mode 100755 index 0000000000000..5fc8828e6e749 --- /dev/null +++ b/compiler/packages/react-forgive/scripts/build.mjs @@ -0,0 +1,58 @@ +#!/usr/bin/env node + +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import * as esbuild from 'esbuild'; +import yargs from 'yargs'; +import * as Server from './server.mjs'; +import * as Client from './client.mjs'; +import path from 'path'; +import {fileURLToPath} from 'url'; + +const IS_DEV = process.env.NODE_ENV === 'development'; +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const argv = yargs(process.argv.slice(2)) + .choices('t', ['client', 'server']) + .options('w', { + alias: 'watch', + default: false, + type: 'boolean', + }) + .parse(); + +async function main() { + if (argv.w) { + const serverCtx = await esbuild.context(Server.config); + const clientCtx = await esbuild.context(Client.config); + await Promise.all([serverCtx.watch(), clientCtx.watch()]); + console.log('watching for changes...'); + } else { + switch (argv.t) { + case 'server': { + await esbuild.build({ + sourcemap: IS_DEV, + minify: IS_DEV === false, + ...Server.config, + }); + break; + } + case 'client': { + await esbuild.build({ + sourcemap: IS_DEV, + minify: IS_DEV === false, + ...Client.config, + }); + break; + } + } + } +} + +main(); diff --git a/compiler/packages/react-forgive/scripts/client.mjs b/compiler/packages/react-forgive/scripts/client.mjs new file mode 100644 index 0000000000000..9a8987061b391 --- /dev/null +++ b/compiler/packages/react-forgive/scripts/client.mjs @@ -0,0 +1,39 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import path from 'path'; +import {fileURLToPath} from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export const entryPoint = path.join(__dirname, '../client/src/extension.ts'); +export const outfile = path.join(__dirname, '../dist/extension.js'); +export const config = { + entryPoints: [entryPoint], + outfile, + bundle: true, + external: ['vscode'], + format: 'cjs', + platform: 'node', + banner: { + js: `/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @lightSyntaxTransform + * @noflow + * @nolint + * @preventMunge + * @preserve-invariant-messages + */ + +`, + }, +}; diff --git a/compiler/packages/react-forgive/scripts/server.mjs b/compiler/packages/react-forgive/scripts/server.mjs new file mode 100644 index 0000000000000..e6d120e341af9 --- /dev/null +++ b/compiler/packages/react-forgive/scripts/server.mjs @@ -0,0 +1,39 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import path from 'path'; +import {fileURLToPath} from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export const entryPoint = path.join(__dirname, '../server/src/index.ts'); +export const outfile = path.join(__dirname, '../dist/server.js'); +export const config = { + entryPoints: [entryPoint], + outfile, + bundle: true, + external: ['vscode'], + format: 'cjs', + platform: 'node', + banner: { + js: `/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @lightSyntaxTransform + * @noflow + * @nolint + * @preventMunge + * @preserve-invariant-messages + */ + +`, + }, +}; diff --git a/compiler/packages/react-forgive/server/package.json b/compiler/packages/react-forgive/server/package.json new file mode 100644 index 0000000000000..fb6f4feebd7ac --- /dev/null +++ b/compiler/packages/react-forgive/server/package.json @@ -0,0 +1,26 @@ +{ + "private": "true", + "name": "react-forgive-server", + "version": "0.0.0", + "description": "Experimental LSP server", + "license": "MIT", + "scripts": { + "build": "rimraf dist && rollup --config --bundleConfigAsCjs", + "test": "echo 'no tests'" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/facebook/react.git", + "directory": "compiler/packages/react-forgive" + }, + "dependencies": { + "@babel/core": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/plugin-syntax-typescript": "^7.25.9", + "@babel/types": "^7.26.0", + "cosmiconfig": "^9.0.0", + "prettier": "^3.3.3", + "vscode-languageserver": "^9.0.1", + "vscode-languageserver-textdocument": "^1.0.12" + } +} diff --git a/compiler/packages/react-forgive/server/src/compiler/compat.ts b/compiler/packages/react-forgive/server/src/compiler/compat.ts new file mode 100644 index 0000000000000..8b13f1df886ea --- /dev/null +++ b/compiler/packages/react-forgive/server/src/compiler/compat.ts @@ -0,0 +1,22 @@ +import {SourceLocation} from 'babel-plugin-react-compiler/src'; +import {type Range} from 'vscode-languageserver'; + +export function babelLocationToRange(loc: SourceLocation): Range | null { + if (typeof loc === 'symbol') { + return null; + } + return { + start: {line: loc.start.line - 1, character: loc.start.column}, + end: {line: loc.end.line - 1, character: loc.end.column}, + }; +} + +/** + * Refine range to only the first character. + */ +export function getRangeFirstCharacter(range: Range): Range { + return { + start: range.start, + end: range.start, + }; +} diff --git a/compiler/packages/react-forgive/server/src/compiler/index.ts b/compiler/packages/react-forgive/server/src/compiler/index.ts new file mode 100644 index 0000000000000..3723785cfbebd --- /dev/null +++ b/compiler/packages/react-forgive/server/src/compiler/index.ts @@ -0,0 +1,66 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type * as BabelCore from '@babel/core'; +import {parseAsync, transformFromAstAsync} from '@babel/core'; +import BabelPluginReactCompiler, { + type PluginOptions, +} from 'babel-plugin-react-compiler/src'; +import * as babelParser from 'prettier/plugins/babel.js'; +import estreeParser from 'prettier/plugins/estree'; +import * as typescriptParser from 'prettier/plugins/typescript'; +import * as prettier from 'prettier/standalone'; + +export let lastResult: BabelCore.BabelFileResult | null = null; + +type CompileOptions = { + text: string; + file: string; + options: PluginOptions | null; +}; +export async function compile({ + text, + file, + options, +}: CompileOptions): Promise { + const ast = await parseAsync(text, { + sourceFileName: file, + parserOpts: { + plugins: ['typescript', 'jsx'], + }, + sourceType: 'module', + }); + if (ast == null) { + return null; + } + const plugins = + options != null + ? [[BabelPluginReactCompiler, options]] + : [[BabelPluginReactCompiler]]; + const result = await transformFromAstAsync(ast, text, { + filename: file, + highlightCode: false, + retainLines: true, + plugins, + sourceType: 'module', + sourceFileName: file, + }); + if (result?.code == null) { + throw new Error( + `Expected BabelPluginReactCompiler to compile successfully, got ${result}`, + ); + } + result.code = await prettier.format(result.code, { + semi: false, + parser: 'babel-ts', + plugins: [babelParser, estreeParser, typescriptParser], + }); + if (result.code != null) { + lastResult = result; + } + return result; +} diff --git a/compiler/packages/react-forgive/server/src/compiler/options.ts b/compiler/packages/react-forgive/server/src/compiler/options.ts new file mode 100644 index 0000000000000..226be799d3abc --- /dev/null +++ b/compiler/packages/react-forgive/server/src/compiler/options.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { + parsePluginOptions, + type PluginOptions, +} from 'babel-plugin-react-compiler/src'; +import {cosmiconfigSync} from 'cosmiconfig'; + +export function resolveReactConfig(projectPath: string): PluginOptions | null { + const explorerSync = cosmiconfigSync('react', { + searchStrategy: 'project', + cache: true, + }); + const result = explorerSync.search(projectPath); + if (result != null) { + return parsePluginOptions(result.config); + } else { + return null; + } +} diff --git a/compiler/packages/react-forgive/server/src/index.ts b/compiler/packages/react-forgive/server/src/index.ts new file mode 100644 index 0000000000000..395969c5e06bf --- /dev/null +++ b/compiler/packages/react-forgive/server/src/index.ts @@ -0,0 +1,123 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {TextDocument} from 'vscode-languageserver-textdocument'; +import { + CodeLens, + createConnection, + type InitializeParams, + type InitializeResult, + ProposedFeatures, + TextDocuments, + TextDocumentSyncKind, +} from 'vscode-languageserver/node'; +import {compile, lastResult} from './compiler'; +import {type PluginOptions} from 'babel-plugin-react-compiler/src'; +import {resolveReactConfig} from './compiler/options'; +import { + CompileSuccessEvent, + defaultOptions, + LoggerEvent, +} from 'babel-plugin-react-compiler/src/Entrypoint/Options'; +import {babelLocationToRange, getRangeFirstCharacter} from './compiler/compat'; + +const SUPPORTED_LANGUAGE_IDS = new Set([ + 'javascript', + 'javascriptreact', + 'typescript', + 'typescriptreact', +]); + +const connection = createConnection(ProposedFeatures.all); +const documents = new TextDocuments(TextDocument); + +let compilerOptions: PluginOptions | null = null; +let compiledFns: Set = new Set(); + +connection.onInitialize((_params: InitializeParams) => { + // TODO(@poteto) get config fr + compilerOptions = resolveReactConfig('.') ?? defaultOptions; + compilerOptions = { + ...compilerOptions, + logger: { + logEvent(_filename: string | null, event: LoggerEvent) { + if (event.kind === 'CompileSuccess') { + compiledFns.add(event); + } + }, + }, + }; + const result: InitializeResult = { + capabilities: { + textDocumentSync: TextDocumentSyncKind.Full, + codeLensProvider: {resolveProvider: true}, + }, + }; + return result; +}); + +connection.onInitialized(() => { + connection.console.log('initialized'); +}); + +documents.onDidChangeContent(async event => { + connection.console.info(`Changed: ${event.document.uri}`); + compiledFns.clear(); + if (SUPPORTED_LANGUAGE_IDS.has(event.document.languageId)) { + const text = event.document.getText(); + await compile({ + text, + file: event.document.uri, + options: compilerOptions, + }); + } +}); + +connection.onDidChangeWatchedFiles(change => { + compiledFns.clear(); + connection.console.log( + change.changes.map(c => `File changed: ${c.uri}`).join('\n'), + ); +}); + +connection.onCodeLens(params => { + connection.console.info(`Handling codelens for: ${params.textDocument.uri}`); + if (compiledFns.size === 0) { + return; + } + const lenses: Array = []; + for (const compiled of compiledFns) { + if (compiled.fnLoc != null) { + const fnLoc = babelLocationToRange(compiled.fnLoc); + if (fnLoc === null) continue; + const lens = CodeLens.create( + getRangeFirstCharacter(fnLoc), + compiled.fnLoc, + ); + if (lastResult?.code != null) { + lens.command = { + title: 'Optimized by React Compiler', + command: 'todo', + }; + } + lenses.push(lens); + } + } + return lenses; +}); + +connection.onCodeLensResolve(lens => { + connection.console.info(`Resolving codelens for: ${JSON.stringify(lens)}`); + if (lastResult?.code != null) { + connection.console.log(lastResult.code); + } + return lens; +}); + +documents.listen(connection); +connection.listen(); +connection.console.info(`React Analyzer running in node ${process.version}`); diff --git a/compiler/packages/react-forgive/server/tsconfig.json b/compiler/packages/react-forgive/server/tsconfig.json new file mode 100644 index 0000000000000..52efba4ebe5af --- /dev/null +++ b/compiler/packages/react-forgive/server/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@tsconfig/strictest/tsconfig.json", + "compilerOptions": { + "module": "ES2015", + "moduleResolution": "Bundler", + "rootDir": "../../..", + "noEmit": true, + "jsx": "react-jsxdev", + "target": "ES2015", + "sourceMap": false, + "removeComments": true, + }, + "exclude": ["node_modules", ".vscode-test"], + "include": ["src/**/*.ts"] +} diff --git a/compiler/packages/react-forgive/server/yarn.lock b/compiler/packages/react-forgive/server/yarn.lock new file mode 100644 index 0000000000000..b72063294ff08 --- /dev/null +++ b/compiler/packages/react-forgive/server/yarn.lock @@ -0,0 +1,410 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/compat-data@^7.25.9": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02" + integrity sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g== + +"@babel/core@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40" + integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.26.0" + "@babel/generator" "^7.26.0" + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helpers" "^7.26.0" + "@babel/parser" "^7.26.0" + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.26.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.26.0", "@babel/generator@^7.26.3": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.3.tgz#ab8d4360544a425c90c248df7059881f4b2ce019" + integrity sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ== + dependencies: + "@babel/parser" "^7.26.3" + "@babel/types" "^7.26.3" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz#55af025ce365be3cdc0c1c1e56c6af617ce88875" + integrity sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ== + dependencies: + "@babel/compat-data" "^7.25.9" + "@babel/helper-validator-option" "^7.25.9" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-module-imports@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-module-transforms@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" + integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/helper-plugin-utils@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz#9cbdd63a9443a2c92a725cca7ebca12cc8dd9f46" + integrity sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw== + +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/helper-validator-option@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" + integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== + +"@babel/helpers@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4" + integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw== + dependencies: + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.0" + +"@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234" + integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA== + dependencies: + "@babel/types" "^7.26.3" + +"@babel/plugin-syntax-typescript@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz#67dda2b74da43727cf21d46cf9afef23f4365399" + integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/template@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" + integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== + dependencies: + "@babel/code-frame" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/traverse@^7.25.9": + version "7.26.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.4.tgz#ac3a2a84b908dde6d463c3bfa2c5fdc1653574bd" + integrity sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.3" + "@babel/parser" "^7.26.3" + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.3" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.3": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0" + integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +browserslist@^4.24.0: + version "4.24.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.3.tgz#5fc2725ca8fb3c1432e13dac278c7cc103e026d2" + integrity sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA== + dependencies: + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" + update-browserslist-db "^1.1.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +caniuse-lite@^1.0.30001688: + version "1.0.30001690" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz#f2d15e3aaf8e18f76b2b8c1481abde063b8104c8" + integrity sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cosmiconfig@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" + integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== + dependencies: + env-paths "^2.2.1" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + +debug@^4.1.0, debug@^4.3.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + +electron-to-chromium@^1.5.73: + version "1.5.74" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.74.tgz#cb886b504a6467e4c00bea3317edb38393c53413" + integrity sha512-ck3//9RC+6oss/1Bh9tiAVFy5vfSKbRHAFh7Z3/eTRkEqJeWgymloShB17Vg3Z4nmDNp35vAd1BZ6CMW4Wt6Iw== + +env-paths@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +import-fresh@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +prettier@^3.3.3: + version "3.4.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f" + integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +update-browserslist-db@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.0" + +vscode-jsonrpc@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz#f43dfa35fb51e763d17cd94dcca0c9458f35abf9" + integrity sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA== + +vscode-languageserver-protocol@3.17.5: + version "3.17.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz#864a8b8f390835572f4e13bd9f8313d0e3ac4bea" + integrity sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg== + dependencies: + vscode-jsonrpc "8.2.0" + vscode-languageserver-types "3.17.5" + +vscode-languageserver-textdocument@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz#457ee04271ab38998a093c68c2342f53f6e4a631" + integrity sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA== + +vscode-languageserver-types@3.17.5: + version "3.17.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz#3273676f0cf2eab40b3f44d085acbb7f08a39d8a" + integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg== + +vscode-languageserver@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz#500aef82097eb94df90d008678b0b6b5f474015b" + integrity sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g== + dependencies: + vscode-languageserver-protocol "3.17.5" + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== diff --git a/compiler/yarn.lock b/compiler/yarn.lock index b5bd5f8eaf7b4..9c25b35b34b81 100644 --- a/compiler/yarn.lock +++ b/compiler/yarn.lock @@ -1851,11 +1851,32 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== +"@eslint-community/regexpp@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": version "4.10.0" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== +"@eslint/config-array@^0.19.0": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.1.tgz#734aaea2c40be22bbb1f2a9dac687c57a6a4c984" + integrity sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA== + dependencies: + "@eslint/object-schema" "^2.1.5" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.9.0": + version "0.9.1" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.9.1.tgz#31763847308ef6b7084a4505573ac9402c51f9d1" + integrity sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q== + dependencies: + "@types/json-schema" "^7.0.15" + "@eslint/eslintrc@^2.1.4": version "2.1.4" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" @@ -1871,6 +1892,21 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/eslintrc@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c" + integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + "@eslint/js@8.57.0": version "8.57.0" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" @@ -1881,6 +1917,23 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== +"@eslint/js@9.17.0", "@eslint/js@^9.13.0": + version "9.17.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.17.0.tgz#1523e586791f80376a6f8398a3964455ecc651ec" + integrity sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w== + +"@eslint/object-schema@^2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.5.tgz#8670a8f6258a2be5b2c620ff314a1d984c23eb2e" + integrity sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ== + +"@eslint/plugin-kit@^0.2.3": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz#2b78e7bb3755784bb13faa8932a1d994d6537792" + integrity sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg== + dependencies: + levn "^0.4.1" + "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" @@ -1893,6 +1946,19 @@ dependencies: "@hapi/hoek" "^9.0.0" +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" + "@humanwhocodes/config-array@^0.11.14": version "0.11.14" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" @@ -1926,6 +1992,16 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b" + integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA== + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -1949,7 +2025,7 @@ js-yaml "^3.13.1" resolve-from "^5.0.0" -"@istanbuljs/schema@^0.1.2": +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== @@ -2812,6 +2888,11 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + "@types/fbt@^1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@types/fbt/-/fbt-1.0.4.tgz#0d9e427f91fcff46bdcf2ca42a63343096565451" @@ -2891,7 +2972,7 @@ "@types/tough-cookie" "*" parse5 "^7.0.0" -"@types/json-schema@*", "@types/json-schema@^7.0.12": +"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -2901,11 +2982,23 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== +"@types/mocha@^10.0.10", "@types/mocha@^10.0.2": + version "10.0.10" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.10.tgz#91f62905e8d23cbd66225312f239454a23bebfa0" + integrity sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q== + "@types/node@*", "@types/node@^18.7.18": version "18.7.19" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.19.tgz#ad83aa9b7af470fab7e0f562be87e97dc8ffe08e" integrity sha512-Sq1itGUKUX1ap7GgZlrzdBydjbsJL/NSQt/4wkAxUJ7/OS5c2WkoN6WSpWc2Yc5wtKMZOUA0VCs/j2XJadN3HA== +"@types/node@^20": + version "20.17.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.10.tgz#3f7166190aece19a0d1d364d75c8b0b5778c1e18" + integrity sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA== + dependencies: + undici-types "~6.19.2" + "@types/node@^20.2.5": version "20.2.5" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.5.tgz#26d295f3570323b2837d322180dfbf1ba156fefb" @@ -2962,6 +3055,11 @@ resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== +"@types/vscode@^1.96.0": + version "1.96.0" + resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.96.0.tgz#3181004bf25d71677ae4aacdd7605a3fd7edf08e" + integrity sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg== + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" @@ -2981,6 +3079,21 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz#992e5ac1553ce20d0d46aa6eccd79dc36dedc805" + integrity sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.18.1" + "@typescript-eslint/type-utils" "8.18.1" + "@typescript-eslint/utils" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + "@typescript-eslint/eslint-plugin@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz#de61c3083842fc6ac889d2fc83c9a96b55ab8328" @@ -3013,6 +3126,17 @@ natural-compare "^1.4.0" ts-api-utils "^1.3.0" +"@typescript-eslint/parser@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.18.1.tgz#c258bae062778b7696793bc492249027a39dfb95" + integrity sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA== + dependencies: + "@typescript-eslint/scope-manager" "8.18.1" + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/typescript-estree" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + debug "^4.3.4" + "@typescript-eslint/parser@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.4.0.tgz#540f4321de1e52b886c0fa68628af1459954c1f1" @@ -3043,6 +3167,14 @@ "@typescript-eslint/types" "7.4.0" "@typescript-eslint/visitor-keys" "7.4.0" +"@typescript-eslint/scope-manager@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz#52cedc3a8178d7464a70beffed3203678648e55b" + integrity sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ== + dependencies: + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + "@typescript-eslint/scope-manager@8.7.0": version "8.7.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz#90ee7bf9bc982b9260b93347c01a8bc2b595e0b8" @@ -3061,6 +3193,16 @@ debug "^4.3.4" ts-api-utils "^1.0.1" +"@typescript-eslint/type-utils@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz#10f41285475c0bdee452b79ff7223f0e43a7781e" + integrity sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ== + dependencies: + "@typescript-eslint/typescript-estree" "8.18.1" + "@typescript-eslint/utils" "8.18.1" + debug "^4.3.4" + ts-api-utils "^1.3.0" + "@typescript-eslint/type-utils@8.7.0": version "8.7.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz#d56b104183bdcffcc434a23d1ce26cde5e42df93" @@ -3076,6 +3218,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.4.0.tgz#ee9dafa75c99eaee49de6dcc9348b45d354419b6" integrity sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw== +"@typescript-eslint/types@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.18.1.tgz#d7f4f94d0bba9ebd088de840266fcd45408a8fff" + integrity sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw== + "@typescript-eslint/types@8.7.0": version "8.7.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.7.0.tgz#21d987201c07b69ce7ddc03451d7196e5445ad19" @@ -3095,6 +3242,20 @@ semver "^7.5.4" ts-api-utils "^1.0.1" +"@typescript-eslint/typescript-estree@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz#2a86cd64b211a742f78dfa7e6f4860413475367e" + integrity sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg== + dependencies: + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + "@typescript-eslint/typescript-estree@8.7.0": version "8.7.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz#6c7db6baa4380b937fa81466c546d052f362d0e8" @@ -3122,6 +3283,16 @@ "@typescript-eslint/typescript-estree" "7.4.0" semver "^7.5.4" +"@typescript-eslint/utils@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.18.1.tgz#c4199ea23fc823c736e2c96fd07b1f7235fa92d5" + integrity sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.18.1" + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/typescript-estree" "8.18.1" + "@typescript-eslint/utils@8.7.0": version "8.7.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.7.0.tgz#cef3f70708b5b5fd7ed8672fc14714472bd8a011" @@ -3140,6 +3311,14 @@ "@typescript-eslint/types" "7.4.0" eslint-visitor-keys "^3.4.1" +"@typescript-eslint/visitor-keys@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz#344b4f6bc83f104f514676facf3129260df7610a" + integrity sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ== + dependencies: + "@typescript-eslint/types" "8.18.1" + eslint-visitor-keys "^4.2.0" + "@typescript-eslint/visitor-keys@8.7.0": version "8.7.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz#5e46f1777f9d69360a883c1a56ac3c511c9659a8" @@ -3153,6 +3332,32 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== +"@vscode/test-cli@^0.0.10": + version "0.0.10" + resolved "https://registry.yarnpkg.com/@vscode/test-cli/-/test-cli-0.0.10.tgz#35f0e81c2e0ff8daceb223e99d1b65306c15822c" + integrity sha512-B0mMH4ia+MOOtwNiLi79XhA+MLmUItIC8FckEuKrVAVriIuSWjt7vv4+bF8qVFiNFe4QRfzPaIZk39FZGWEwHA== + dependencies: + "@types/mocha" "^10.0.2" + c8 "^9.1.0" + chokidar "^3.5.3" + enhanced-resolve "^5.15.0" + glob "^10.3.10" + minimatch "^9.0.3" + mocha "^10.2.0" + supports-color "^9.4.0" + yargs "^17.7.2" + +"@vscode/test-electron@^2.4.1": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-2.4.1.tgz#5c2760640bf692efbdaa18bafcd35fb519688941" + integrity sha512-Gc6EdaLANdktQ1t+zozoBVRynfIsMKMc94Svu1QreOBC8y76x4tvaK32TljrLi1LI2+PK58sDVbL7ALdqf3VRQ== + dependencies: + http-proxy-agent "^7.0.2" + https-proxy-agent "^7.0.5" + jszip "^3.10.1" + ora "^7.0.1" + semver "^7.6.2" + abab@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" @@ -3186,6 +3391,11 @@ acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.14.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== + acorn@^8.4.1, acorn@^8.7.1: version "8.8.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" @@ -3203,6 +3413,11 @@ agent-base@6: dependencies: debug "4" +agent-base@^7.1.0, agent-base@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" + integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== + ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -3213,6 +3428,11 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -3267,6 +3487,14 @@ anymatch@^3.0.3: normalize-path "^3.0.0" picomatch "^2.0.4" +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -3526,6 +3754,11 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -3535,6 +3768,15 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" +bl@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-5.1.0.tgz#183715f678c7188ecef9fe475d90209400624273" + integrity sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ== + dependencies: + buffer "^6.0.3" + inherits "^2.0.4" + readable-stream "^3.4.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -3550,7 +3792,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.3: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -3562,6 +3804,11 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== +browser-stdout@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + browserslist@^4.21.3, browserslist@^4.21.5: version "4.21.7" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.7.tgz#e2b420947e5fb0a58e8f4668ae6e23488127e551" @@ -3609,6 +3856,31 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +c8@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/c8/-/c8-9.1.0.tgz#0e57ba3ab9e5960ab1d650b4a86f71e53cb68112" + integrity sha512-mBWcT5iqNir1zIkzSPyI3NCR9EZCVI3WUD+AVO17MVWTSFNyUueXE82qTeampNtTr+ilN/5Ua3j24LgbCKjDVg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@istanbuljs/schema" "^0.1.3" + find-up "^5.0.0" + foreground-child "^3.1.1" + istanbul-lib-coverage "^3.2.0" + istanbul-lib-report "^3.0.1" + istanbul-reports "^3.1.6" + test-exclude "^6.0.0" + v8-to-istanbul "^9.0.0" + yargs "^17.7.2" + yargs-parser "^21.1.1" + call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -3632,7 +3904,7 @@ camelcase@^5.0.0, camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.2.0: +camelcase@^6.0.0, camelcase@^6.2.0: version "6.3.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== @@ -3664,11 +3936,31 @@ chalk@4, chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.0.0, chalk@^5.3.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8" + integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + ci-info@^3.2.0: version "3.4.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.4.0.tgz#b28484fd436cbc267900364f096c9dc185efb251" @@ -3693,7 +3985,14 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" -cli-spinners@^2.5.0: +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" + integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== + dependencies: + restore-cursor "^4.0.0" + +cli-spinners@^2.5.0, cli-spinners@^2.9.0: version "2.9.2" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== @@ -3853,6 +4152,11 @@ core-js-compat@^3.30.1, core-js-compat@^3.30.2: dependencies: browserslist "^4.21.5" +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -3867,6 +4171,15 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + cssom@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" @@ -3928,11 +4241,23 @@ debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, d dependencies: ms "2.1.2" +debug@^4.3.5: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + decimal.js@^10.3.1: version "10.4.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.1.tgz#be75eeac4a2281aace80c1a8753587c27ef053e7" @@ -4008,6 +4333,11 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +diff@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== + difflib@~0.2.1: version "0.2.4" resolved "https://registry.yarnpkg.com/difflib/-/difflib-0.2.4.tgz#b5e30361a6db023176d562892db85940a718f47e" @@ -4073,6 +4403,11 @@ emittery@^0.13.1: resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== +emoji-regex@^10.2.1: + version "10.4.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.4.0.tgz#03553afea80b3975749cfcb36f776ca268e413d4" + integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -4088,6 +4423,14 @@ enabled@2.0.x: resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== +enhanced-resolve@^5.15.0: + version "5.18.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz#91eb1db193896b9801251eeff1c6980278b1e404" + integrity sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + entities@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" @@ -4181,6 +4524,14 @@ eslint-scope@^7.2.2: esrecurse "^4.3.0" estraverse "^5.2.0" +eslint-scope@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442" + integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + eslint-visitor-keys@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" @@ -4196,6 +4547,11 @@ eslint-visitor-keys@^3.4.3: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== +eslint-visitor-keys@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" + integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== + eslint@8.57.0: version "8.57.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" @@ -4284,6 +4640,55 @@ eslint@^8.57.1: strip-ansi "^6.0.1" text-table "^0.2.0" +eslint@^9.13.0: + version "9.17.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.17.0.tgz#faa1facb5dd042172fdc520106984b5c2421bb0c" + integrity sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.19.0" + "@eslint/core" "^0.9.0" + "@eslint/eslintrc" "^3.2.0" + "@eslint/js" "9.17.0" + "@eslint/plugin-kit" "^0.2.3" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@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.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + 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 "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +espree@^10.0.1, espree@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" + integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== + dependencies: + acorn "^8.14.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.0" + espree@^9.6.0, espree@^9.6.1: version "9.6.1" resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" @@ -4305,6 +4710,13 @@ esquery@^1.4.2: dependencies: estraverse "^5.1.0" +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" @@ -4470,6 +4882,13 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + fill-range@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" @@ -4535,11 +4954,29 @@ flat-cache@^3.0.4: flatted "^3.1.0" rimraf "^3.0.2" +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + flatted@^3.1.0: version "3.2.7" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== +flatted@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + flow-enums-runtime@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/flow-enums-runtime/-/flow-enums-runtime-0.0.4.tgz#038635c679030d08d4c197db29a2fad62722072f" @@ -4571,6 +5008,14 @@ foreground-child@^3.1.0: cross-spawn "^7.0.0" signal-exit "^4.0.1" +foreground-child@^3.1.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -4599,6 +5044,11 @@ fsevents@^2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -4633,7 +5083,7 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -glob-parent@^5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -4658,7 +5108,7 @@ glob@^10.3.10: minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-scurry "^1.10.1" -glob@^10.3.7: +glob@^10.3.7, glob@^10.4.5: version "10.4.5" resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== @@ -4682,6 +5132,17 @@ glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + global-modules@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" @@ -4714,6 +5175,11 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -4726,7 +5192,7 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -4770,6 +5236,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + "heap@>= 0.2.0": version "0.2.7" resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc" @@ -4836,6 +5307,14 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" +http-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -4844,6 +5323,14 @@ https-proxy-agent@^5.0.1: agent-base "6" debug "4" +https-proxy-agent@^7.0.5: + version "7.0.6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== + dependencies: + agent-base "^7.1.2" + debug "4" + human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -4856,7 +5343,7 @@ iconv-lite@0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.13: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -4876,6 +5363,11 @@ ignore@^5.3.1: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -4905,7 +5397,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@^2.0.4: +inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4932,6 +5424,13 @@ is-arrayish@^0.3.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-core-module@^2.11.0: version "2.12.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" @@ -4961,7 +5460,7 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -4973,6 +5472,11 @@ is-interactive@^1.0.0: resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== +is-interactive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-2.0.0.tgz#40c57614593826da1100ade6059778d597f16e90" + integrity sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ== + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -4983,6 +5487,11 @@ is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -5005,11 +5514,21 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +is-unicode-supported@^1.1.0, is-unicode-supported@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714" + integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ== + is-windows@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -5045,6 +5564,15 @@ istanbul-lib-report@^3.0.0: make-dir "^3.0.0" supports-color "^7.1.0" +istanbul-lib-report@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + istanbul-lib-source-maps@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" @@ -5062,6 +5590,14 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +istanbul-reports@^3.1.6: + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + jackspeak@^2.3.5: version "2.3.6" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" @@ -6277,6 +6813,11 @@ jsesc@~0.5.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-diff@^0.5.4: version "0.5.5" resolved "https://registry.yarnpkg.com/json-diff/-/json-diff-0.5.5.tgz#24658ad200dbdd64ae8a56baf4d87b2b33d7196e" @@ -6313,11 +6854,28 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jszip@^3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + keypress@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/keypress/-/keypress-0.2.1.tgz#1e80454250018dbad4c3fe94497d6e67b6269c77" integrity sha512-HjorDJFNhnM4SicvaUXac0X77NiskggxJdesG72+O5zBKpSqKFCrqmndKVqpu3pFqkla0St6uGk8Ju0sCurrmg== +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -6359,6 +6917,13 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -6414,6 +6979,14 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" +log-symbols@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-5.1.0.tgz#a20e3b9a5f53fac6aeb8e2bb22c07cf2c8f16d93" + integrity sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA== + dependencies: + chalk "^5.0.0" + is-unicode-supported "^1.1.0" + logform@^2.6.0, logform@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/logform/-/logform-2.7.0.tgz#cfca97528ef290f2e125a08396805002b2d060d1" @@ -6477,6 +7050,13 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + make-error@1.x, make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -6543,20 +7123,20 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - dependencies: - brace-expansion "^2.0.1" - -minimatch@~5.1.2: +minimatch@^5.0.1, minimatch@^5.1.6, minimatch@~5.1.2: version "5.1.6" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.3, minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -6577,6 +7157,58 @@ mkdirp@3.0.1: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== +mocha@^10.2.0: + version "10.8.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.8.2.tgz#8d8342d016ed411b12a429eb731b825f961afb96" + integrity sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^8.1.0" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" + +mocha@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-11.0.1.tgz#85c1c0e806275fe2479245be4ac4a0d81f533aa8" + integrity sha512-+3GkODfsDG71KSCQhc4IekSW+ItCK/kiez1Z28ksWvYhKXV/syxMlerR/sC7whDp7IyreZ4YxceMLdTs5hQE8A== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^10.4.5" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" + mri@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" @@ -6587,7 +7219,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -6634,7 +7266,7 @@ node-releases@^2.0.19: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== -normalize-path@^3.0.0: +normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== @@ -6780,6 +7412,21 @@ ora@5.4.1: strip-ansi "^6.0.0" wcwidth "^1.0.1" +ora@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-7.0.1.tgz#cdd530ecd865fe39e451a0e7697865669cb11930" + integrity sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw== + dependencies: + chalk "^5.3.0" + cli-cursor "^4.0.0" + cli-spinners "^2.9.0" + is-interactive "^2.0.0" + is-unicode-supported "^1.3.0" + log-symbols "^5.1.0" + stdin-discarder "^0.1.0" + string-width "^6.1.0" + strip-ansi "^7.1.0" + p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -6825,6 +7472,11 @@ package-json-from-dist@^1.0.0: resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== +pako@~1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -6917,7 +7569,7 @@ picocolors@^1.1.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -7017,6 +7669,11 @@ pretty-format@^29.5.0: ansi-styles "^5.0.0" react-is "^18.0.0" +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + prompt-promise@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/prompt-promise/-/prompt-promise-1.0.3.tgz#78ce4fcb9a14a108c49174f2d808c440d1bde265" @@ -7073,6 +7730,13 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + react-dom@0.0.0-experimental-4beb1fd8-20241118: version "0.0.0-experimental-4beb1fd8-20241118" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-4beb1fd8-20241118.tgz#bf51483d52faea0618abef7d7eab681eea328ac7" @@ -7114,6 +7778,26 @@ readable-stream@^3.4.0, readable-stream@^3.6.2: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + readline@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c" @@ -7243,6 +7927,14 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" + integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -7274,16 +7966,16 @@ rxjs@^7.0.0, rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@~5.2.0: +safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + safe-stable-stringify@^2.3.1: version "2.5.0" resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" @@ -7335,11 +8027,18 @@ semver@^7.5.3, semver@^7.5.4: dependencies: lru-cache "^6.0.0" -semver@^7.6.0: +semver@^7.6.0, semver@^7.6.2: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + serializerr@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/serializerr/-/serializerr-1.0.3.tgz#12d4c5aa1c3ffb8f6d1dc5f395aa9455569c3f91" @@ -7352,6 +8051,11 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -7451,6 +8155,13 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" +stdin-discarder@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/stdin-discarder/-/stdin-discarder-0.1.0.tgz#22b3e400393a8e28ebf53f9958f3880622efde21" + integrity sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ== + dependencies: + bl "^5.0.0" + string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -7486,6 +8197,15 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" +string-width@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-6.1.0.tgz#96488d6ed23f9ad5d82d13522af9e4c4c3fd7518" + integrity sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^10.2.1" + strip-ansi "^7.0.1" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -7493,6 +8213,13 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -7507,7 +8234,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.0.1: +strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== @@ -7543,13 +8270,18 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0, supports-color@^8.1.0: +supports-color@^8.0.0, supports-color@^8.1.0, supports-color@^8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" +supports-color@^9.4.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.4.0.tgz#17bfcf686288f531db3dea3215510621ccb55954" + integrity sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw== + supports-hyperlinks@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" @@ -7568,6 +8300,11 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== +tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" @@ -7747,11 +8484,25 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== +typescript-eslint@^8.16.0: + version "8.18.1" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.18.1.tgz#197b284b6769678ed77d9868df180eeaf61108eb" + integrity sha512-Mlaw6yxuaDEPQvb/2Qwu3/TfgeBHy9iTJ3mTwe7OvpPmF6KPQjVOfGyEJpPv6Ez2C34OODChhXrzYw/9phI0MQ== + dependencies: + "@typescript-eslint/eslint-plugin" "8.18.1" + "@typescript-eslint/parser" "8.18.1" + "@typescript-eslint/utils" "8.18.1" + typescript@^5.4.3: version "5.4.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff" integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" @@ -7816,7 +8567,7 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" -util-deprecate@^1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -7826,6 +8577,15 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +v8-to-istanbul@^9.0.0: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + v8-to-istanbul@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" @@ -7969,6 +8729,11 @@ wordwrap@>=0.0.2: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -8061,11 +8826,26 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^20.2.2, yargs-parser@^20.2.9: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yargs-parser@^21.0.0, yargs-parser@^21.0.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== +yargs-unparser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + yargs@^15.3.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" @@ -8083,6 +8863,19 @@ yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.2" +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yargs@^17.3.1: version "17.5.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" diff --git a/fixtures/eslint-v9/eslint.config.mjs b/fixtures/eslint-v9/eslint.config.ts similarity index 76% rename from fixtures/eslint-v9/eslint.config.mjs rename to fixtures/eslint-v9/eslint.config.ts index ffc8375265c2b..62ef68671639e 100644 --- a/fixtures/eslint-v9/eslint.config.mjs +++ b/fixtures/eslint-v9/eslint.config.ts @@ -1,3 +1,4 @@ +import type {Linter} from 'eslint'; import * as reactHooks from 'eslint-plugin-react-hooks'; export default [ @@ -12,10 +13,10 @@ export default [ }, }, }, - reactHooks.configs['recommended-latest'], + reactHooks.configs['recommended'], { rules: { 'react-hooks/exhaustive-deps': 'error', }, }, -]; +] satisfies Linter.Config[]; diff --git a/fixtures/eslint-v9/package.json b/fixtures/eslint-v9/package.json index 58d0a94c0c58c..80827a0d1730a 100644 --- a/fixtures/eslint-v9/package.json +++ b/fixtures/eslint-v9/package.json @@ -2,8 +2,9 @@ "private": true, "name": "eslint-v9", "dependencies": { - "eslint": "^9", - "eslint-plugin-react-hooks": "link:../../build/oss-stable/eslint-plugin-react-hooks" + "eslint": "^9.18.0", + "eslint-plugin-react-hooks": "link:../../build/oss-stable/eslint-plugin-react-hooks", + "jiti": "^2.4.2" }, "scripts": { "build": "node build.mjs && yarn", diff --git a/fixtures/eslint-v9/tsconfig.json b/fixtures/eslint-v9/tsconfig.json new file mode 100644 index 0000000000000..2c63c0851048d --- /dev/null +++ b/fixtures/eslint-v9/tsconfig.json @@ -0,0 +1,2 @@ +{ +} diff --git a/fixtures/eslint-v9/yarn.lock b/fixtures/eslint-v9/yarn.lock index 1583b73f14e21..a473b3a4ce165 100644 --- a/fixtures/eslint-v9/yarn.lock +++ b/fixtures/eslint-v9/yarn.lock @@ -14,7 +14,7 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== -"@eslint/config-array@^0.19.0": +"@eslint/config-array@^0.19.2": version "0.19.2" resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa" integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w== @@ -23,24 +23,17 @@ debug "^4.3.1" minimatch "^3.1.2" -"@eslint/core@^0.10.0": - version "0.10.0" - resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.10.0.tgz#23727063c21b335f752dbb3a16450f6f9cbc9091" - integrity sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw== +"@eslint/core@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.12.0.tgz#5f960c3d57728be9f6c65bd84aa6aa613078798e" + integrity sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg== dependencies: "@types/json-schema" "^7.0.15" -"@eslint/core@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.11.0.tgz#7a9226e850922e42cbd2ba71361eacbe74352a12" - integrity sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA== - dependencies: - "@types/json-schema" "^7.0.15" - -"@eslint/eslintrc@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c" - integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w== +"@eslint/eslintrc@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.0.tgz#96a558f45842989cca7ea1ecd785ad5491193846" + integrity sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -52,22 +45,22 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@9.20.0": - version "9.20.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.20.0.tgz#7421bcbe74889fcd65d1be59f00130c289856eb4" - integrity sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ== +"@eslint/js@9.21.0": + version "9.21.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.21.0.tgz#4303ef4e07226d87c395b8fad5278763e9c15c08" + integrity sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw== "@eslint/object-schema@^2.1.6": version "2.1.6" resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f" integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA== -"@eslint/plugin-kit@^0.2.5": - version "0.2.5" - resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz#ee07372035539e7847ef834e3f5e7b79f09e3a81" - integrity sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A== +"@eslint/plugin-kit@^0.2.7": + version "0.2.7" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz#9901d52c136fb8f375906a73dcc382646c3b6a27" + integrity sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g== dependencies: - "@eslint/core" "^0.10.0" + "@eslint/core" "^0.12.0" levn "^0.4.1" "@humanfs/core@^0.19.1": @@ -93,10 +86,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== -"@humanwhocodes/retry@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b" - integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA== +"@humanwhocodes/retry@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.2.tgz#1860473de7dfa1546767448f333db80cb0ff2161" + integrity sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ== "@types/estree@^1.0.6": version "1.0.6" @@ -231,21 +224,21 @@ eslint-visitor-keys@^4.2.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== -eslint@^9: - version "9.20.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.20.1.tgz#923924c078f5226832449bac86662dd7e53c91d6" - integrity sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g== +eslint@^9.18.0: + version "9.21.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.21.0.tgz#b1c9c16f5153ff219791f627b94ab8f11f811591" + integrity sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@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" + "@eslint/config-array" "^0.19.2" + "@eslint/core" "^0.12.0" + "@eslint/eslintrc" "^3.3.0" + "@eslint/js" "9.21.0" + "@eslint/plugin-kit" "^0.2.7" "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" - "@humanwhocodes/retry" "^0.4.1" + "@humanwhocodes/retry" "^0.4.2" "@types/estree" "^1.0.6" "@types/json-schema" "^7.0.15" ajv "^6.12.4" @@ -399,6 +392,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +jiti@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" + integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== + js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" diff --git a/fixtures/view-transition/src/components/SwipeRecognizer.js b/fixtures/view-transition/src/components/SwipeRecognizer.js index f332796fc8cdf..8e913dfb4e55f 100644 --- a/fixtures/view-transition/src/components/SwipeRecognizer.js +++ b/fixtures/view-transition/src/components/SwipeRecognizer.js @@ -33,11 +33,6 @@ export default function SwipeRecognizer({ }); } function onScrollEnd() { - if (activeGesture.current !== null) { - const cancelGesture = activeGesture.current; - activeGesture.current = null; - cancelGesture(); - } let changed; const scrollElement = scrollRef.current; if (axis === 'x') { @@ -60,6 +55,11 @@ export default function SwipeRecognizer({ // Trigger side-effects startTransition(action); } + if (activeGesture.current !== null) { + const cancelGesture = activeGesture.current; + activeGesture.current = null; + cancelGesture(); + } } useEffect(() => { diff --git a/packages/eslint-plugin-react-hooks/README.md b/packages/eslint-plugin-react-hooks/README.md index 36f63722f7268..e4223c18b20e0 100644 --- a/packages/eslint-plugin-react-hooks/README.md +++ b/packages/eslint-plugin-react-hooks/README.md @@ -18,9 +18,22 @@ npm install eslint-plugin-react-hooks --save-dev yarn add eslint-plugin-react-hooks --dev ``` +### Flat Config (eslint.config.js|ts) + +For [ESLint 9.0.0 and above](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/), add the `recommended` config. + +```js +import * as reactHooks from 'eslint-plugin-react-hooks'; + +export default [ + // ... + reactHooks.configs['recommended'], +]; +``` + ### Legacy Config (.eslintrc) -If you are still using ESLint below 9.0.0, please continue to use `recommended-legacy`. To avoid breaking changes, we still support `recommended` as well, but note that this will be changed to alias the flat recommended config in v6. +If you are still using ESLint below 9.0.0, you can use `recommended-legacy` for accessing the recommended config. ```js { @@ -31,25 +44,29 @@ If you are still using ESLint below 9.0.0, please continue to use `recommended-l } ``` -### Flat Config (eslint.config.js) +### Custom Configuration + +If you want more fine-grained configuration, you can instead add a snippet like this to your ESLint configuration file: -For [ESLint 9.0.0 and above](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/) users, add the `recommended-latest` config. +#### Flat Config (eslint.config.js|ts) ```js -import reactHooks from 'eslint-plugin-react-hooks'; +import * as reactHooks from 'eslint-plugin-react-hooks'; export default [ - // ... - reactHooks.configs['recommended-latest'], + { + files: ['**/*.{js,jsx}'], + plugins: { 'react-hooks': reactHooks }, + // ... + rules: { + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', + } + }, ]; ``` -### Custom Configuration - -If you want more fine-grained configuration, you can instead add a snippet like this to your ESLint configuration file: - #### Legacy Config (.eslintrc) - ```js { "plugins": [ @@ -64,24 +81,6 @@ If you want more fine-grained configuration, you can instead add a snippet like } ``` -#### Flat Config (eslint.config.js) - -```js -import reactHooks from 'eslint-plugin-react-hooks'; - -export default [ - { - files: ['**/*.{js,jsx}'], - plugins: { 'react-hooks': reactHooks }, - // ... - rules: { - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'warn', - } - }, -]; -``` - ## Advanced Configuration `exhaustive-deps` can be configured to validate dependencies of custom Hooks with the `additionalHooks` option. @@ -89,10 +88,10 @@ This option accepts a regex to match the names of custom Hooks that have depende ```js { - "rules": { + rules: { // ... "react-hooks/exhaustive-deps": ["warn", { - "additionalHooks": "(useMyCustomHook|useMyOtherCustomHook)" + additionalHooks: "(useMyCustomHook|useMyOtherCustomHook)" }] } } diff --git a/packages/eslint-plugin-react-hooks/package.json b/packages/eslint-plugin-react-hooks/package.json index d3717b9dee61c..48cb7ae452a8d 100644 --- a/packages/eslint-plugin-react-hooks/package.json +++ b/packages/eslint-plugin-react-hooks/package.json @@ -31,7 +31,7 @@ "main": "./index.js", "types": "./index.d.ts", "engines": { - "node": ">=10" + "node": ">=18" }, "homepage": "https://react.dev/", "peerDependencies": { diff --git a/packages/eslint-plugin-react-hooks/src/index.ts b/packages/eslint-plugin-react-hooks/src/index.ts index 42b55320fcd89..61ac62912ddc2 100644 --- a/packages/eslint-plugin-react-hooks/src/index.ts +++ b/packages/eslint-plugin-react-hooks/src/index.ts @@ -4,8 +4,8 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -import RulesOfHooks from './RulesOfHooks'; -import ExhaustiveDeps from './ExhaustiveDeps'; +import RulesOfHooks from './rules/RulesOfHooks'; +import ExhaustiveDeps from './rules/ExhaustiveDeps'; import type {ESLint, Linter, Rule} from 'eslint'; // All rules @@ -20,11 +20,16 @@ const configRules = { 'react-hooks/exhaustive-deps': 'warn', } satisfies Linter.RulesRecord; -// Legacy config -const legacyRecommendedConfig = { - plugins: ['react-hooks'], +// Flat config +const recommendedConfig = { + name: 'react-hooks/recommended', + plugins: { + get 'react-hooks'(): ESLint.Plugin { + return plugin; + }, + }, rules: configRules, -} satisfies Linter.LegacyConfig; +}; // Plugin object const plugin = { @@ -34,24 +39,18 @@ const plugin = { rules, configs: { /** Legacy recommended config, to be used with rc-based configurations */ - 'recommended-legacy': legacyRecommendedConfig, + 'recommended-legacy': { + plugins: ['react-hooks'], + rules: configRules, + }, /** - * 'recommended' is currently aliased to the legacy / rc recommended config) to maintain backwards compatibility. - * This is deprecated and in v6, it will switch to alias the flat recommended config. + * Recommended config, to be used with flat configs. */ - recommended: legacyRecommendedConfig, + recommended: recommendedConfig, - /** Latest recommended config, to be used with flat configurations */ - 'recommended-latest': { - name: 'react-hooks/recommended', - plugins: { - get 'react-hooks'(): ESLint.Plugin { - return plugin; - }, - }, - rules: configRules, - }, + /** @deprecated please use `recommended`; will be removed in v7 */ + 'recommended-latest': recommendedConfig, }, } satisfies ESLint.Plugin; diff --git a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.ts b/packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts similarity index 100% rename from packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.ts rename to packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts diff --git a/packages/eslint-plugin-react-hooks/src/RulesOfHooks.ts b/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts similarity index 100% rename from packages/eslint-plugin-react-hooks/src/RulesOfHooks.ts rename to packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts diff --git a/packages/react-art/src/ReactFiberConfigART.js b/packages/react-art/src/ReactFiberConfigART.js index a011bdf5c71c7..dc746b0e17d88 100644 --- a/packages/react-art/src/ReactFiberConfigART.js +++ b/packages/react-art/src/ReactFiberConfigART.js @@ -500,6 +500,12 @@ export function startViewTransition() { return false; } +export type RunningGestureTransition = null; + +export function startGestureTransition() {} + +export function stopGestureTransition(transition: RunningGestureTransition) {} + export type ViewTransitionInstance = null | {name: string, ...}; export function createViewTransitionInstance( diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js index 87f98b99f2534..79ec20c3c2975 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js @@ -1553,7 +1553,7 @@ describe('ReactHooksInspectionIntegration', () => { expect(tree[0].id).toEqual(0); expect(tree[0].isStateEditable).toEqual(false); expect(tree[0].name).toEqual('Id'); - expect(String(tree[0].value).startsWith(':r')).toBe(true); + expect(String(tree[0].value).startsWith('\u00ABr')).toBe(true); expect(normalizeSourceLoc(tree)[1]).toMatchInlineSnapshot(` { diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 52560d0b006b0..2b288efe46c3f 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -1394,7 +1394,10 @@ export function startViewTransition( transition.ready.then(spawnedWorkCallback, spawnedWorkCallback); transition.finished.then(() => { // $FlowFixMe[prop-missing] - ownerDocument.__reactViewTransition = null; + if (ownerDocument.__reactViewTransition === transition) { + // $FlowFixMe[prop-missing] + ownerDocument.__reactViewTransition = null; + } passiveCallback(); }); return true; @@ -1409,6 +1412,75 @@ export function startViewTransition( } } +export type RunningGestureTransition = { + skipTransition(): void, + ... +}; + +export function startGestureTransition( + rootContainer: Container, + transitionTypes: null | TransitionTypes, + mutationCallback: () => void, + animateCallback: () => void, +): null | RunningGestureTransition { + const ownerDocument: Document = + rootContainer.nodeType === DOCUMENT_NODE + ? (rootContainer: any) + : rootContainer.ownerDocument; + try { + // $FlowFixMe[prop-missing] + const transition = ownerDocument.startViewTransition({ + update: mutationCallback, + types: transitionTypes, + }); + // $FlowFixMe[prop-missing] + ownerDocument.__reactViewTransition = transition; + let blockingAnim = null; + const readyCallback = () => { + // View Transitions with ScrollTimeline has a quirk where they end if the + // ScrollTimeline ever reaches 100% but that doesn't mean we're done because + // you can swipe back again. We can prevent this by adding a paused Animation + // that never stops. This seems to keep all running Animations alive until + // we explicitly abort (or something forces the View Transition to cancel). + const documentElement: Element = (ownerDocument.documentElement: any); + blockingAnim = documentElement.animate([{}, {}], { + pseudoElement: '::view-transition', + duration: 1, + }); + blockingAnim.pause(); + animateCallback(); + }; + transition.ready.then(readyCallback, readyCallback); + transition.finished.then(() => { + if (blockingAnim !== null) { + // In Safari, we need to manually clear this or it'll block future transitions. + blockingAnim.cancel(); + } + // $FlowFixMe[prop-missing] + if (ownerDocument.__reactViewTransition === transition) { + // $FlowFixMe[prop-missing] + ownerDocument.__reactViewTransition = null; + } + }); + return transition; + } catch (x) { + // We use the error as feature detection. + // The only thing that should throw is if startViewTransition is missing + // or if it doesn't accept the object form. Other errors are async. + // I.e. it's before the View Transitions v2 spec. We only support View + // Transitions v2 otherwise we fallback to not animating to ensure that + // we're not animating with the wrong animation mapped. + // Run through the sequence to put state back into a consistent state. + mutationCallback(); + animateCallback(); + return null; + } +} + +export function stopGestureTransition(transition: RunningGestureTransition) { + transition.skipTransition(); +} + interface ViewTransitionPseudoElementType extends Animatable { _scope: HTMLElement; _selector: string; diff --git a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js index 6a86cbb2652fa..963f516b15308 100644 --- a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js +++ b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js @@ -858,7 +858,7 @@ export function makeId( ): string { const idPrefix = resumableState.idPrefix; - let id = ':' + idPrefix + 'R' + treeId; + let id = '\u00AB' + idPrefix + 'R' + treeId; // Unless this is the first id at this level, append a number at the end // that represents the position of this useId hook among all the useId @@ -867,7 +867,7 @@ export function makeId( id += 'H' + localId.toString(32); } - return id + ':'; + return id + '\u00BB'; } function encodeHTMLTextNode(text: string): string { diff --git a/packages/react-dom/src/__tests__/ReactDOMUseId-test.js b/packages/react-dom/src/__tests__/ReactDOMUseId-test.js index af5dbdd355294..7738994fb1e1e 100644 --- a/packages/react-dom/src/__tests__/ReactDOMUseId-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMUseId-test.js @@ -96,7 +96,7 @@ describe('useId', () => { } function normalizeTreeIdForTesting(id) { - const result = id.match(/:(R|r)([a-z0-9]*)(H([0-9]*))?:/); + const result = id.match(/\u00AB(R|r)([a-z0-9]*)(H([0-9]*))?\u00BB/); if (result === undefined) { throw new Error('Invalid id format'); } @@ -285,7 +285,7 @@ describe('useId', () => { // 'R:' prefix, and the first character after that, which may not correspond // to a complete set of 5 bits. // - // Example: :Rclalalalalalalala...: + // Example: «Rclalalalalalalala...: // // We can use this pattern to test large ids that exceed the bitwise // safe range (32 bits). The algorithm should theoretically support ids @@ -320,8 +320,8 @@ describe('useId', () => { // Confirm that every id matches the expected pattern for (let i = 0; i < divs.length; i++) { - // Example: :Rclalalalalalalala...: - expect(divs[i].id).toMatch(/^:R.(((al)*a?)((la)*l?))*:$/); + // Example: «Rclalalalalalalala...: + expect(divs[i].id).toMatch(/^\u00ABR.(((al)*a?)((la)*l?))*\u00BB$/); } }); @@ -345,7 +345,7 @@ describe('useId', () => {
- :R0:, :R0H1:, :R0H2: + «R0», «R0H1», «R0H2»
`); }); @@ -370,7 +370,7 @@ describe('useId', () => {
- :R0: + «R0»
`); }); @@ -608,10 +608,10 @@ describe('useId', () => { id="container" >
- :custom-prefix-R1: + «custom-prefix-R1»
- :custom-prefix-R2: + «custom-prefix-R2»
`); @@ -625,13 +625,13 @@ describe('useId', () => { id="container" >
- :custom-prefix-R1: + «custom-prefix-R1»
- :custom-prefix-R2: + «custom-prefix-R2»
- :custom-prefix-r0: + «custom-prefix-r0»
`); @@ -672,11 +672,11 @@ describe('useId', () => { id="container" >
- :R0: + «R0»
- :R7: + «R7»
@@ -690,11 +690,11 @@ describe('useId', () => { id="container" >
- :R0: + «R0»
- :R7: + «R7»
diff --git a/packages/react-native-renderer/src/ReactFiberConfigNative.js b/packages/react-native-renderer/src/ReactFiberConfigNative.js index 00385547f23e7..4a9064c82a83b 100644 --- a/packages/react-native-renderer/src/ReactFiberConfigNative.js +++ b/packages/react-native-renderer/src/ReactFiberConfigNative.js @@ -597,6 +597,21 @@ export function startViewTransition( return false; } +export type RunningGestureTransition = null; + +export function startGestureTransition( + rootContainer: Container, + transitionTypes: null | TransitionTypes, + mutationCallback: () => void, + animateCallback: () => void, +): RunningGestureTransition { + mutationCallback(); + animateCallback(); + return null; +} + +export function stopGestureTransition(transition: RunningGestureTransition) {} + export type ViewTransitionInstance = null | {name: string, ...}; export function createViewTransitionInstance( diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index 43853a864fb5e..e392ad7b0c04f 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -93,6 +93,8 @@ export type TransitionStatus = mixed; export type FormInstance = Instance; +export type RunningGestureTransition = null; + export type ViewTransitionInstance = null | {name: string, ...}; export type GestureTimeline = null; @@ -792,6 +794,19 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { return false; }, + startGestureTransition( + rootContainer: Container, + transitionTypes: null | TransitionTypes, + mutationCallback: () => void, + animateCallback: () => void, + ): RunningGestureTransition { + mutationCallback(); + animateCallback(); + return null; + }, + + stopGestureTransition(transition: RunningGestureTransition) {}, + createViewTransitionInstance(name: string): ViewTransitionInstance { return null; }, diff --git a/packages/react-reconciler/src/ReactFiberApplyGesture.js b/packages/react-reconciler/src/ReactFiberApplyGesture.js new file mode 100644 index 0000000000000..46af2ca4309fa --- /dev/null +++ b/packages/react-reconciler/src/ReactFiberApplyGesture.js @@ -0,0 +1,42 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import type {Fiber, FiberRoot} from './ReactInternalTypes'; + +import { + cancelRootViewTransitionName, + restoreRootViewTransitionName, +} from './ReactFiberConfig'; + +// Clone View Transition boundaries that have any mutations or might have had their +// layout affected by child insertions. +export function insertDestinationClones( + root: FiberRoot, + finishedWork: Fiber, +): void { + // TODO +} + +// Revert insertions and apply view transition names to the "new" (current) state. +export function applyDepartureTransitions( + root: FiberRoot, + finishedWork: Fiber, +): void { + // TODO + cancelRootViewTransitionName(root.containerInfo); +} + +// Revert transition names and start/adjust animations on the started View Transition. +export function startGestureAnimations( + root: FiberRoot, + finishedWork: Fiber, +): void { + // TODO + restoreRootViewTransitionName(root.containerInfo); +} diff --git a/packages/react-reconciler/src/ReactFiberCommitViewTransitions.js b/packages/react-reconciler/src/ReactFiberCommitViewTransitions.js new file mode 100644 index 0000000000000..22b9d11ac67d2 --- /dev/null +++ b/packages/react-reconciler/src/ReactFiberCommitViewTransitions.js @@ -0,0 +1,831 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import type {Instance, InstanceMeasurement, Props} from './ReactFiberConfig'; +import type {Fiber} from './ReactInternalTypes'; +import type { + ViewTransitionProps, + ViewTransitionState, +} from './ReactFiberViewTransitionComponent'; + +import { + HostComponent, + OffscreenComponent, + ViewTransitionComponent, +} from './ReactWorkTags'; +import { + NoFlags, + Update, + ViewTransitionStatic, + AffectedParentLayout, + ViewTransitionNamedStatic, +} from './ReactFiberFlags'; +import { + supportsMutation, + applyViewTransitionName, + restoreViewTransitionName, + measureInstance, + hasInstanceChanged, + hasInstanceAffectedParent, + wasInstanceInViewport, +} from './ReactFiberConfig'; +import {scheduleViewTransitionEvent} from './ReactFiberWorkLoop'; +import { + getViewTransitionName, + getViewTransitionClassName, +} from './ReactFiberViewTransitionComponent'; + +export let shouldStartViewTransition: boolean = false; + +export function resetShouldStartViewTransition(): void { + shouldStartViewTransition = false; +} + +// This tracks named ViewTransition components found in the accumulateSuspenseyCommit +// phase that might need to find deleted pairs in the beforeMutation phase. +let appearingViewTransitions: Map | null = null; + +export function resetAppearingViewTransitions(): void { + appearingViewTransitions = null; +} + +export function trackAppearingViewTransition( + name: string, + state: ViewTransitionState, +): void { + if (appearingViewTransitions === null) { + appearingViewTransitions = new Map(); + } + appearingViewTransitions.set(name, state); +} + +// We can't cancel view transition children until we know that their parent also +// don't need to transition. +export let viewTransitionCancelableChildren: null | Array< + Instance | string | Props, +> = null; // tupled array where each entry is [instance: Instance, oldName: string, props: Props] + +export function setViewTransitionCancelableChildren( + children: null | Array, +): void { + viewTransitionCancelableChildren = children; +} + +let viewTransitionHostInstanceIdx = 0; + +function applyViewTransitionToHostInstances( + child: null | Fiber, + name: string, + className: ?string, + collectMeasurements: null | Array, + stopAtNestedViewTransitions: boolean, +): boolean { + if (!supportsMutation) { + return false; + } + let inViewport = false; + while (child !== null) { + if (child.tag === HostComponent) { + shouldStartViewTransition = true; + const instance: Instance = child.stateNode; + if (collectMeasurements !== null) { + const measurement = measureInstance(instance); + collectMeasurements.push(measurement); + if (wasInstanceInViewport(measurement)) { + inViewport = true; + } + } else if (!inViewport) { + if (wasInstanceInViewport(measureInstance(instance))) { + inViewport = true; + } + } + applyViewTransitionName( + instance, + viewTransitionHostInstanceIdx === 0 + ? name + : // If we have multiple Host Instances below, we add a suffix to the name to give + // each one a unique name. + name + '_' + viewTransitionHostInstanceIdx, + className, + ); + viewTransitionHostInstanceIdx++; + } else if ( + child.tag === OffscreenComponent && + child.memoizedState !== null + ) { + // Skip any hidden subtrees. They were or are effectively not there. + } else if ( + child.tag === ViewTransitionComponent && + stopAtNestedViewTransitions + ) { + // Skip any nested view transitions for updates since in that case the + // inner most one is the one that handles the update. + } else { + if ( + applyViewTransitionToHostInstances( + child.child, + name, + className, + collectMeasurements, + stopAtNestedViewTransitions, + ) + ) { + inViewport = true; + } + } + child = child.sibling; + } + return inViewport; +} + +function restoreViewTransitionOnHostInstances( + child: null | Fiber, + stopAtNestedViewTransitions: boolean, +): void { + if (!supportsMutation) { + return; + } + while (child !== null) { + if (child.tag === HostComponent) { + const instance: Instance = child.stateNode; + restoreViewTransitionName(instance, child.memoizedProps); + } else if ( + child.tag === OffscreenComponent && + child.memoizedState !== null + ) { + // Skip any hidden subtrees. They were or are effectively not there. + } else if ( + child.tag === ViewTransitionComponent && + stopAtNestedViewTransitions + ) { + // Skip any nested view transitions for updates since in that case the + // inner most one is the one that handles the update. + } else { + restoreViewTransitionOnHostInstances( + child.child, + stopAtNestedViewTransitions, + ); + } + child = child.sibling; + } +} + +function commitAppearingPairViewTransitions(placement: Fiber): void { + if ((placement.subtreeFlags & ViewTransitionNamedStatic) === NoFlags) { + // This has no named view transitions in its subtree. + return; + } + let child = placement.child; + while (child !== null) { + if (child.tag === OffscreenComponent && child.memoizedState === null) { + // This tree was already hidden so we skip it. + } else { + commitAppearingPairViewTransitions(child); + if ( + child.tag === ViewTransitionComponent && + (child.flags & ViewTransitionNamedStatic) !== NoFlags + ) { + const instance: ViewTransitionState = child.stateNode; + if (instance.paired) { + const props: ViewTransitionProps = child.memoizedProps; + if (props.name == null || props.name === 'auto') { + throw new Error( + 'Found a pair with an auto name. This is a bug in React.', + ); + } + const name = props.name; + const className: ?string = getViewTransitionClassName( + props.className, + props.share, + ); + if (className !== 'none') { + // We found a new appearing view transition with the same name as this deletion. + // We'll transition between them. + viewTransitionHostInstanceIdx = 0; + const inViewport = applyViewTransitionToHostInstances( + child.child, + name, + className, + null, + false, + ); + if (!inViewport) { + // This boundary is exiting within the viewport but is going to leave the viewport. + // Instead, we treat this as an exit of the previous entry by reverting the new name. + // Ideally we could undo the old transition but it's now too late. It's also on its + // on snapshot. We have know was for it to paint onto the original group. + // TODO: This will lead to things unexpectedly having exit animations that normally + // wouldn't happen. Consider if we should just let this fly off the screen instead. + restoreViewTransitionOnHostInstances(child.child, false); + } + } + } + } + } + child = child.sibling; + } +} + +export function commitEnterViewTransitions(placement: Fiber): void { + if (placement.tag === ViewTransitionComponent) { + const state: ViewTransitionState = placement.stateNode; + const props: ViewTransitionProps = placement.memoizedProps; + const name = getViewTransitionName(props, state); + const className: ?string = getViewTransitionClassName( + props.className, + state.paired ? props.share : props.enter, + ); + if (className !== 'none') { + viewTransitionHostInstanceIdx = 0; + const inViewport = applyViewTransitionToHostInstances( + placement.child, + name, + className, + null, + false, + ); + if (!inViewport) { + // TODO: If this was part of a pair we will still run the onShare callback. + // Revert the transition names. This boundary is not in the viewport + // so we won't bother animating it. + restoreViewTransitionOnHostInstances(placement.child, false); + // TODO: Should we still visit the children in case a named one was in the viewport? + } else { + commitAppearingPairViewTransitions(placement); + + if (!state.paired) { + scheduleViewTransitionEvent(placement, props.onEnter); + } + } + } else { + commitAppearingPairViewTransitions(placement); + } + } else if ((placement.subtreeFlags & ViewTransitionStatic) !== NoFlags) { + let child = placement.child; + while (child !== null) { + commitEnterViewTransitions(child); + child = child.sibling; + } + } else { + commitAppearingPairViewTransitions(placement); + } +} + +function commitDeletedPairViewTransitions(deletion: Fiber): void { + if ( + appearingViewTransitions === null || + appearingViewTransitions.size === 0 + ) { + // We've found all. + return; + } + const pairs = appearingViewTransitions; + if ((deletion.subtreeFlags & ViewTransitionNamedStatic) === NoFlags) { + // This has no named view transitions in its subtree. + return; + } + let child = deletion.child; + while (child !== null) { + if (child.tag === OffscreenComponent && child.memoizedState === null) { + // This tree was already hidden so we skip it. + } else { + if ( + child.tag === ViewTransitionComponent && + (child.flags & ViewTransitionNamedStatic) !== NoFlags + ) { + const props: ViewTransitionProps = child.memoizedProps; + const name = props.name; + if (name != null && name !== 'auto') { + const pair = pairs.get(name); + if (pair !== undefined) { + const className: ?string = getViewTransitionClassName( + props.className, + props.share, + ); + if (className !== 'none') { + // We found a new appearing view transition with the same name as this deletion. + viewTransitionHostInstanceIdx = 0; + const inViewport = applyViewTransitionToHostInstances( + child.child, + name, + className, + null, + false, + ); + if (!inViewport) { + // This boundary is not in the viewport so we won't treat it as a matched pair. + // Revert the transition names. This avoids it flying onto the screen which can + // be disruptive and doesn't really preserve any continuity anyway. + restoreViewTransitionOnHostInstances(child.child, false); + } else { + // We'll transition between them. + const oldinstance: ViewTransitionState = child.stateNode; + const newInstance: ViewTransitionState = pair; + newInstance.paired = oldinstance; + // Note: If the other side ends up outside the viewport, we'll still run this. + // Therefore it's possible for onShare to be called with only an old snapshot. + scheduleViewTransitionEvent(child, props.onShare); + } + } + // Delete the entry so that we know when we've found all of them + // and can stop searching (size reaches zero). + pairs.delete(name); + if (pairs.size === 0) { + break; + } + } + } + } + commitDeletedPairViewTransitions(child); + } + child = child.sibling; + } +} + +export function commitExitViewTransitions(deletion: Fiber): void { + if (deletion.tag === ViewTransitionComponent) { + const props: ViewTransitionProps = deletion.memoizedProps; + const name = getViewTransitionName(props, deletion.stateNode); + const pair = + appearingViewTransitions !== null + ? appearingViewTransitions.get(name) + : undefined; + const className: ?string = getViewTransitionClassName( + props.className, + pair !== undefined ? props.share : props.exit, + ); + if (className !== 'none') { + viewTransitionHostInstanceIdx = 0; + const inViewport = applyViewTransitionToHostInstances( + deletion.child, + name, + className, + null, + false, + ); + if (!inViewport) { + // Revert the transition names. This boundary is not in the viewport + // so we won't bother animating it. + restoreViewTransitionOnHostInstances(deletion.child, false); + // TODO: Should we still visit the children in case a named one was in the viewport? + } else if (pair !== undefined) { + // We found a new appearing view transition with the same name as this deletion. + // We'll transition between them instead of running the normal exit. + const oldinstance: ViewTransitionState = deletion.stateNode; + const newInstance: ViewTransitionState = pair; + newInstance.paired = oldinstance; + // Delete the entry so that we know when we've found all of them + // and can stop searching (size reaches zero). + // $FlowFixMe[incompatible-use]: Refined by the pair. + appearingViewTransitions.delete(name); + // Note: If the other side ends up outside the viewport, we'll still run this. + // Therefore it's possible for onShare to be called with only an old snapshot. + scheduleViewTransitionEvent(deletion, props.onShare); + } else { + scheduleViewTransitionEvent(deletion, props.onExit); + } + } + if (appearingViewTransitions !== null) { + // Look for more pairs deeper in the tree. + commitDeletedPairViewTransitions(deletion); + } + } else if ((deletion.subtreeFlags & ViewTransitionStatic) !== NoFlags) { + let child = deletion.child; + while (child !== null) { + commitExitViewTransitions(child); + child = child.sibling; + } + } else { + if (appearingViewTransitions !== null) { + commitDeletedPairViewTransitions(deletion); + } + } +} + +export function commitBeforeUpdateViewTransition( + current: Fiber, + finishedWork: Fiber, +): void { + // The way we deal with multiple HostInstances as children of a View Transition in an + // update can get tricky. The important bit is that if you swap out n HostInstances + // from n HostInstances then they match up in order. Similarly, if you don't swap + // any HostInstances each instance just transitions as is. + // + // We call this function twice. First we apply the view transition names on the + // "current" tree in the snapshot phase. Then in the mutation phase we apply view + // transition names to the "finishedWork" tree. + // + // This means that if there were insertions or deletions before an updated Instance + // that same Instance might get different names in the "old" and the "new" state. + // For example if you swap two HostInstances inside a ViewTransition they don't + // animate to swap position but rather cross-fade into the other instance. This might + // be unexpected but it is in line with the semantics that the ViewTransition is its + // own layer that cross-fades its content when it updates. If you want to reorder then + // each child needs its own ViewTransition. + const oldProps: ViewTransitionProps = current.memoizedProps; + const oldName = getViewTransitionName(oldProps, current.stateNode); + const newProps: ViewTransitionProps = finishedWork.memoizedProps; + // This className applies only if there are fewer child DOM nodes than + // before or if this update should've been cancelled but we ended up with + // a parent animating so we need to animate the child too. + // For example, if update="foo" layout="none" and it turns out this was + // a layout only change, then the "foo" class will be applied even though + // it was not actually an update. Which is a bug. + let className: ?string = getViewTransitionClassName( + newProps.className, + newProps.update, + ); + if (className === 'none') { + className = getViewTransitionClassName(newProps.className, newProps.layout); + if (className === 'none') { + // If both update and layout are both "none" then we don't have to + // apply a name. Since we won't animate this boundary. + return; + } + } + viewTransitionHostInstanceIdx = 0; + applyViewTransitionToHostInstances( + current.child, + oldName, + className, + (current.memoizedState = []), + true, + ); +} + +export function commitNestedViewTransitions(changedParent: Fiber): void { + let child = changedParent.child; + while (child !== null) { + if (child.tag === ViewTransitionComponent) { + // In this case the outer ViewTransition component wins but if there + // was an update through this component then the inner one wins. + const props: ViewTransitionProps = child.memoizedProps; + const name = getViewTransitionName(props, child.stateNode); + const className: ?string = getViewTransitionClassName( + props.className, + props.layout, + ); + if (className !== 'none') { + viewTransitionHostInstanceIdx = 0; + applyViewTransitionToHostInstances( + child.child, + name, + className, + (child.memoizedState = []), + false, + ); + } + } else if ((child.subtreeFlags & ViewTransitionStatic) !== NoFlags) { + commitNestedViewTransitions(child); + } + child = child.sibling; + } +} + +function restorePairedViewTransitions(parent: Fiber): void { + if ((parent.subtreeFlags & ViewTransitionNamedStatic) === NoFlags) { + // This has no named view transitions in its subtree. + return; + } + let child = parent.child; + while (child !== null) { + if (child.tag === OffscreenComponent && child.memoizedState === null) { + // This tree was already hidden so we skip it. + } else { + if ( + child.tag === ViewTransitionComponent && + (child.flags & ViewTransitionNamedStatic) !== NoFlags + ) { + const instance: ViewTransitionState = child.stateNode; + if (instance.paired !== null) { + instance.paired = null; + restoreViewTransitionOnHostInstances(child.child, false); + } + } + restorePairedViewTransitions(child); + } + child = child.sibling; + } +} + +export function restoreEnterViewTransitions(placement: Fiber): void { + if (placement.tag === ViewTransitionComponent) { + const instance: ViewTransitionState = placement.stateNode; + instance.paired = null; + restoreViewTransitionOnHostInstances(placement.child, false); + restorePairedViewTransitions(placement); + } else if ((placement.subtreeFlags & ViewTransitionStatic) !== NoFlags) { + let child = placement.child; + while (child !== null) { + restoreEnterViewTransitions(child); + child = child.sibling; + } + } else { + restorePairedViewTransitions(placement); + } +} + +export function restoreExitViewTransitions(deletion: Fiber): void { + if (deletion.tag === ViewTransitionComponent) { + const instance: ViewTransitionState = deletion.stateNode; + instance.paired = null; + restoreViewTransitionOnHostInstances(deletion.child, false); + restorePairedViewTransitions(deletion); + } else if ((deletion.subtreeFlags & ViewTransitionStatic) !== NoFlags) { + let child = deletion.child; + while (child !== null) { + restoreExitViewTransitions(child); + child = child.sibling; + } + } else { + restorePairedViewTransitions(deletion); + } +} + +export function restoreUpdateViewTransition( + current: Fiber, + finishedWork: Fiber, +): void { + finishedWork.memoizedState = null; + restoreViewTransitionOnHostInstances(current.child, true); + restoreViewTransitionOnHostInstances(finishedWork.child, true); +} + +export function restoreNestedViewTransitions(changedParent: Fiber): void { + let child = changedParent.child; + while (child !== null) { + if (child.tag === ViewTransitionComponent) { + child.memoizedState = null; + restoreViewTransitionOnHostInstances(child.child, false); + } else if ((child.subtreeFlags & ViewTransitionStatic) !== NoFlags) { + restoreNestedViewTransitions(child); + } + child = child.sibling; + } +} + +function cancelViewTransitionHostInstances( + currentViewTransition: Fiber, + child: null | Fiber, + stopAtNestedViewTransitions: boolean, +): void { + if (!supportsMutation) { + return; + } + while (child !== null) { + if (child.tag === HostComponent) { + const instance: Instance = child.stateNode; + const oldName = getViewTransitionName( + currentViewTransition.memoizedProps, + currentViewTransition.stateNode, + ); + if (viewTransitionCancelableChildren === null) { + viewTransitionCancelableChildren = []; + } + viewTransitionCancelableChildren.push( + instance, + oldName, + child.memoizedProps, + ); + viewTransitionHostInstanceIdx++; + } else if ( + child.tag === OffscreenComponent && + child.memoizedState !== null + ) { + // Skip any hidden subtrees. They were or are effectively not there. + } else if ( + child.tag === ViewTransitionComponent && + stopAtNestedViewTransitions + ) { + // Skip any nested view transitions for updates since in that case the + // inner most one is the one that handles the update. + } else { + cancelViewTransitionHostInstances( + currentViewTransition, + child.child, + stopAtNestedViewTransitions, + ); + } + child = child.sibling; + } +} + +function measureViewTransitionHostInstances( + currentViewTransition: Fiber, + parentViewTransition: Fiber, + child: null | Fiber, + name: string, + className: ?string, + previousMeasurements: null | Array, + stopAtNestedViewTransitions: boolean, +): boolean { + if (!supportsMutation) { + return true; + } + let inViewport = false; + while (child !== null) { + if (child.tag === HostComponent) { + const instance: Instance = child.stateNode; + if ( + previousMeasurements !== null && + viewTransitionHostInstanceIdx < previousMeasurements.length + ) { + // The previous measurement of the Instance in this location within the ViewTransition. + // Note that this might not be the same exact Instance if the Instances within the + // ViewTransition changed. + const previousMeasurement = + previousMeasurements[viewTransitionHostInstanceIdx]; + const nextMeasurement = measureInstance(instance); + if ( + wasInstanceInViewport(previousMeasurement) || + wasInstanceInViewport(nextMeasurement) + ) { + // If either the old or new state was within the viewport we have to animate this. + // But if it turns out that none of them were we'll be able to skip it. + inViewport = true; + } + if ( + (parentViewTransition.flags & Update) === NoFlags && + hasInstanceChanged(previousMeasurement, nextMeasurement) + ) { + parentViewTransition.flags |= Update; + } + if (hasInstanceAffectedParent(previousMeasurement, nextMeasurement)) { + // If this instance size within its parent has changed it might have caused the + // parent to relayout which needs a cross fade. + parentViewTransition.flags |= AffectedParentLayout; + } + } else { + // If there was an insertion of extra nodes, we have to assume they affected the parent. + // It should have already been marked as an Update due to the mutation. + parentViewTransition.flags |= AffectedParentLayout; + } + if ((parentViewTransition.flags & Update) !== NoFlags) { + // We might update this node so we need to apply its new name for the new state. + applyViewTransitionName( + instance, + viewTransitionHostInstanceIdx === 0 + ? name + : // If we have multiple Host Instances below, we add a suffix to the name to give + // each one a unique name. + name + '_' + viewTransitionHostInstanceIdx, + className, + ); + } + if (!inViewport || (parentViewTransition.flags & Update) === NoFlags) { + // It turns out that we had no other deeper mutations, the child transitions didn't + // affect the parent layout and this instance hasn't changed size. So we can skip + // animating it. However, in the current model this only works if the parent also + // doesn't animate. So we have to queue these and wait until we complete the parent + // to cancel them. + const oldName = getViewTransitionName( + currentViewTransition.memoizedProps, + currentViewTransition.stateNode, + ); + if (viewTransitionCancelableChildren === null) { + viewTransitionCancelableChildren = []; + } + viewTransitionCancelableChildren.push( + instance, + oldName, + child.memoizedProps, + ); + } + viewTransitionHostInstanceIdx++; + } else if ( + child.tag === OffscreenComponent && + child.memoizedState !== null + ) { + // Skip any hidden subtrees. They were or are effectively not there. + } else if ( + child.tag === ViewTransitionComponent && + stopAtNestedViewTransitions + ) { + // Skip any nested view transitions for updates since in that case the + // inner most one is the one that handles the update. + // If this inner boundary resized we need to bubble that information up. + parentViewTransition.flags |= child.flags & AffectedParentLayout; + } else { + if ( + measureViewTransitionHostInstances( + currentViewTransition, + parentViewTransition, + child.child, + name, + className, + previousMeasurements, + stopAtNestedViewTransitions, + ) + ) { + inViewport = true; + } + } + child = child.sibling; + } + return inViewport; +} + +export function measureUpdateViewTransition( + current: Fiber, + finishedWork: Fiber, +): boolean { + const props: ViewTransitionProps = finishedWork.memoizedProps; + const updateClassName: ?string = getViewTransitionClassName( + props.className, + props.update, + ); + const layoutClassName: ?string = getViewTransitionClassName( + props.className, + props.layout, + ); + let className: ?string; + if (updateClassName === 'none') { + if (layoutClassName === 'none') { + // If both update and layout class name were none, then we didn't apply any + // names in the before update phase so we shouldn't now neither. + return false; + } + // We don't care if this is mutated or children layout changed, but we still + // measure each instance to see if it moved and therefore should apply layout. + finishedWork.flags &= ~Update; + className = layoutClassName; + } else if ((finishedWork.flags & Update) !== NoFlags) { + // It was updated and we have an appropriate class name to apply. + className = updateClassName; + } else { + if (layoutClassName === 'none') { + // If we did not update, then all changes are considered a layout. We'll + // attempt to cancel. + viewTransitionHostInstanceIdx = 0; + cancelViewTransitionHostInstances(current, finishedWork.child, true); + return false; + } + // We didn't update but we might still apply layout so we measure each + // instance to see if it moved or resized. + className = layoutClassName; + } + const name = getViewTransitionName(props, finishedWork.stateNode); + // If nothing changed due to a mutation, or children changing size + // and the measurements end up unchanged, we should restore it to not animate. + viewTransitionHostInstanceIdx = 0; + const previousMeasurements = current.memoizedState; + const inViewport = measureViewTransitionHostInstances( + current, + finishedWork, + finishedWork.child, + name, + className, + previousMeasurements, + true, + ); + const previousCount = + previousMeasurements === null ? 0 : previousMeasurements.length; + if (viewTransitionHostInstanceIdx !== previousCount) { + // If we found a different number of child DOM nodes we need to assume that + // the parent layout may have changed as a result. This is not necessarily + // true if those nodes were absolutely positioned. + finishedWork.flags |= AffectedParentLayout; + } + return inViewport; +} + +export function measureNestedViewTransitions(changedParent: Fiber): void { + let child = changedParent.child; + while (child !== null) { + if (child.tag === ViewTransitionComponent) { + const current = child.alternate; + if (current !== null) { + const props: ViewTransitionProps = child.memoizedProps; + const name = getViewTransitionName(props, child.stateNode); + const className: ?string = getViewTransitionClassName( + props.className, + props.layout, + ); + viewTransitionHostInstanceIdx = 0; + const inViewport = measureViewTransitionHostInstances( + current, + child, + child.child, + name, + className, + child.memoizedState, + false, + ); + if ((child.flags & Update) === NoFlags || !inViewport) { + // Nothing changed. + } else { + scheduleViewTransitionEvent(child, props.onLayout); + } + } + } else if ((child.subtreeFlags & ViewTransitionStatic) !== NoFlags) { + measureNestedViewTransitions(child); + } + child = child.sibling; + } +} diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 850f3c67067ff..f5d0987393046 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -14,7 +14,6 @@ import type { Container, HoistableRoot, FormInstance, - InstanceMeasurement, Props, } from './ReactFiberConfig'; import type {Fiber, FiberRoot} from './ReactInternalTypes'; @@ -112,9 +111,7 @@ import { PerformedWork, ForceClientRender, DidCapture, - ViewTransitionStatic, AffectedParentLayout, - ViewTransitionNamedStatic, } from './ReactFiberFlags'; import { commitStartTime, @@ -163,15 +160,9 @@ import { suspendResource, resetFormInstance, registerSuspenseInstanceRetry, - applyViewTransitionName, - restoreViewTransitionName, cancelViewTransitionName, cancelRootViewTransitionName, restoreRootViewTransitionName, - measureInstance, - hasInstanceChanged, - hasInstanceAffectedParent, - wasInstanceInViewport, isSingletonScope, } from './ReactFiberConfig'; import { @@ -203,10 +194,6 @@ import { OffscreenDetached, OffscreenPassiveEffectsConnected, } from './ReactFiberActivityComponent'; -import { - getViewTransitionName, - getViewTransitionClassName, -} from './ReactFiberViewTransitionComponent'; import { TransitionRoot, TransitionTracingMarker, @@ -249,6 +236,23 @@ import { commitHostSingletonAcquisition, commitHostSingletonRelease, } from './ReactFiberCommitHostEffects'; +import { + commitEnterViewTransitions, + commitExitViewTransitions, + commitBeforeUpdateViewTransition, + commitNestedViewTransitions, + restoreEnterViewTransitions, + restoreExitViewTransitions, + restoreUpdateViewTransition, + restoreNestedViewTransitions, + measureUpdateViewTransition, + measureNestedViewTransitions, + resetShouldStartViewTransition, + resetAppearingViewTransitions, + trackAppearingViewTransition, + viewTransitionCancelableChildren, + setViewTransitionCancelableChildren, +} from './ReactFiberCommitViewTransitions'; import { viewTransitionMutationContext, pushMutationContext, @@ -274,19 +278,9 @@ let inProgressRoot: FiberRoot | null = null; let focusedInstanceHandle: null | Fiber = null; export let shouldFireAfterActiveInstanceBlur: boolean = false; -export let shouldStartViewTransition: boolean = false; - -// This tracks named ViewTransition components found in the accumulateSuspenseyCommit -// phase that might need to find deleted pairs in the beforeMutation phase. -let appearingViewTransitions: Map | null = null; - // Used during the commit phase to track whether a parent ViewTransition component // might have been affected by any mutations / relayouts below. let viewTransitionContextChanged: boolean = false; -// We can't cancel view transition children until we know that their parent also -// don't need to transition. -let viewTransitionCancelableChildren: null | Array = - null; // tupled array where each entry is [instance: Instance, oldName: string, props: Props] export function commitBeforeMutationEffects( root: FiberRoot, @@ -295,7 +289,8 @@ export function commitBeforeMutationEffects( ): void { focusedInstanceHandle = prepareForCommit(root.containerInfo); shouldFireAfterActiveInstanceBlur = false; - shouldStartViewTransition = false; + + resetShouldStartViewTransition(); const isViewTransitionEligible = enableViewTransition && @@ -307,7 +302,7 @@ export function commitBeforeMutationEffects( // We no longer need to track the active instance fiber focusedInstanceHandle = null; // We've found any matched pairs and can now reset. - appearingViewTransitions = null; + resetAppearingViewTransitions(); } function commitBeforeMutationEffects_begin(isViewTransitionEligible: boolean) { @@ -542,759 +537,6 @@ function commitBeforeMutationEffectsDeletion( } } -let viewTransitionHostInstanceIdx = 0; - -function applyViewTransitionToHostInstances( - child: null | Fiber, - name: string, - className: ?string, - collectMeasurements: null | Array, - stopAtNestedViewTransitions: boolean, -): boolean { - if (!supportsMutation) { - return false; - } - let inViewport = false; - while (child !== null) { - if (child.tag === HostComponent) { - shouldStartViewTransition = true; - const instance: Instance = child.stateNode; - if (collectMeasurements !== null) { - const measurement = measureInstance(instance); - collectMeasurements.push(measurement); - if (wasInstanceInViewport(measurement)) { - inViewport = true; - } - } else if (!inViewport) { - if (wasInstanceInViewport(measureInstance(instance))) { - inViewport = true; - } - } - applyViewTransitionName( - instance, - viewTransitionHostInstanceIdx === 0 - ? name - : // If we have multiple Host Instances below, we add a suffix to the name to give - // each one a unique name. - name + '_' + viewTransitionHostInstanceIdx, - className, - ); - viewTransitionHostInstanceIdx++; - } else if ( - child.tag === OffscreenComponent && - child.memoizedState !== null - ) { - // Skip any hidden subtrees. They were or are effectively not there. - } else if ( - child.tag === ViewTransitionComponent && - stopAtNestedViewTransitions - ) { - // Skip any nested view transitions for updates since in that case the - // inner most one is the one that handles the update. - } else { - if ( - applyViewTransitionToHostInstances( - child.child, - name, - className, - collectMeasurements, - stopAtNestedViewTransitions, - ) - ) { - inViewport = true; - } - } - child = child.sibling; - } - return inViewport; -} - -function restoreViewTransitionOnHostInstances( - child: null | Fiber, - stopAtNestedViewTransitions: boolean, -): void { - if (!supportsMutation) { - return; - } - while (child !== null) { - if (child.tag === HostComponent) { - const instance: Instance = child.stateNode; - restoreViewTransitionName(instance, child.memoizedProps); - } else if ( - child.tag === OffscreenComponent && - child.memoizedState !== null - ) { - // Skip any hidden subtrees. They were or are effectively not there. - } else if ( - child.tag === ViewTransitionComponent && - stopAtNestedViewTransitions - ) { - // Skip any nested view transitions for updates since in that case the - // inner most one is the one that handles the update. - } else { - restoreViewTransitionOnHostInstances( - child.child, - stopAtNestedViewTransitions, - ); - } - child = child.sibling; - } -} - -function commitAppearingPairViewTransitions(placement: Fiber): void { - if ((placement.subtreeFlags & ViewTransitionNamedStatic) === NoFlags) { - // This has no named view transitions in its subtree. - return; - } - let child = placement.child; - while (child !== null) { - if (child.tag === OffscreenComponent && child.memoizedState === null) { - // This tree was already hidden so we skip it. - } else { - commitAppearingPairViewTransitions(child); - if ( - child.tag === ViewTransitionComponent && - (child.flags & ViewTransitionNamedStatic) !== NoFlags - ) { - const instance: ViewTransitionState = child.stateNode; - if (instance.paired) { - const props: ViewTransitionProps = child.memoizedProps; - if (props.name == null || props.name === 'auto') { - throw new Error( - 'Found a pair with an auto name. This is a bug in React.', - ); - } - const name = props.name; - const className: ?string = getViewTransitionClassName( - props.className, - props.share, - ); - if (className !== 'none') { - // We found a new appearing view transition with the same name as this deletion. - // We'll transition between them. - viewTransitionHostInstanceIdx = 0; - const inViewport = applyViewTransitionToHostInstances( - child.child, - name, - className, - null, - false, - ); - if (!inViewport) { - // This boundary is exiting within the viewport but is going to leave the viewport. - // Instead, we treat this as an exit of the previous entry by reverting the new name. - // Ideally we could undo the old transition but it's now too late. It's also on its - // on snapshot. We have know was for it to paint onto the original group. - // TODO: This will lead to things unexpectedly having exit animations that normally - // wouldn't happen. Consider if we should just let this fly off the screen instead. - restoreViewTransitionOnHostInstances(child.child, false); - } - } - } - } - } - child = child.sibling; - } -} - -function commitEnterViewTransitions(placement: Fiber): void { - if (placement.tag === ViewTransitionComponent) { - const state: ViewTransitionState = placement.stateNode; - const props: ViewTransitionProps = placement.memoizedProps; - const name = getViewTransitionName(props, state); - const className: ?string = getViewTransitionClassName( - props.className, - state.paired ? props.share : props.enter, - ); - if (className !== 'none') { - viewTransitionHostInstanceIdx = 0; - const inViewport = applyViewTransitionToHostInstances( - placement.child, - name, - className, - null, - false, - ); - if (!inViewport) { - // TODO: If this was part of a pair we will still run the onShare callback. - // Revert the transition names. This boundary is not in the viewport - // so we won't bother animating it. - restoreViewTransitionOnHostInstances(placement.child, false); - // TODO: Should we still visit the children in case a named one was in the viewport? - } else { - commitAppearingPairViewTransitions(placement); - - if (!state.paired) { - scheduleViewTransitionEvent(placement, props.onEnter); - } - } - } else { - commitAppearingPairViewTransitions(placement); - } - } else if ((placement.subtreeFlags & ViewTransitionStatic) !== NoFlags) { - let child = placement.child; - while (child !== null) { - commitEnterViewTransitions(child); - child = child.sibling; - } - } else { - commitAppearingPairViewTransitions(placement); - } -} - -function commitDeletedPairViewTransitions(deletion: Fiber): void { - if ( - appearingViewTransitions === null || - appearingViewTransitions.size === 0 - ) { - // We've found all. - return; - } - const pairs = appearingViewTransitions; - if ((deletion.subtreeFlags & ViewTransitionNamedStatic) === NoFlags) { - // This has no named view transitions in its subtree. - return; - } - let child = deletion.child; - while (child !== null) { - if (child.tag === OffscreenComponent && child.memoizedState === null) { - // This tree was already hidden so we skip it. - } else { - if ( - child.tag === ViewTransitionComponent && - (child.flags & ViewTransitionNamedStatic) !== NoFlags - ) { - const props: ViewTransitionProps = child.memoizedProps; - const name = props.name; - if (name != null && name !== 'auto') { - const pair = pairs.get(name); - if (pair !== undefined) { - const className: ?string = getViewTransitionClassName( - props.className, - props.share, - ); - if (className !== 'none') { - // We found a new appearing view transition with the same name as this deletion. - viewTransitionHostInstanceIdx = 0; - const inViewport = applyViewTransitionToHostInstances( - child.child, - name, - className, - null, - false, - ); - if (!inViewport) { - // This boundary is not in the viewport so we won't treat it as a matched pair. - // Revert the transition names. This avoids it flying onto the screen which can - // be disruptive and doesn't really preserve any continuity anyway. - restoreViewTransitionOnHostInstances(child.child, false); - } else { - // We'll transition between them. - const oldinstance: ViewTransitionState = child.stateNode; - const newInstance: ViewTransitionState = pair; - newInstance.paired = oldinstance; - // Note: If the other side ends up outside the viewport, we'll still run this. - // Therefore it's possible for onShare to be called with only an old snapshot. - scheduleViewTransitionEvent(child, props.onShare); - } - } - // Delete the entry so that we know when we've found all of them - // and can stop searching (size reaches zero). - pairs.delete(name); - if (pairs.size === 0) { - break; - } - } - } - } - commitDeletedPairViewTransitions(child); - } - child = child.sibling; - } -} - -function commitExitViewTransitions(deletion: Fiber): void { - if (deletion.tag === ViewTransitionComponent) { - const props: ViewTransitionProps = deletion.memoizedProps; - const name = getViewTransitionName(props, deletion.stateNode); - const pair = - appearingViewTransitions !== null - ? appearingViewTransitions.get(name) - : undefined; - const className: ?string = getViewTransitionClassName( - props.className, - pair !== undefined ? props.share : props.exit, - ); - if (className !== 'none') { - viewTransitionHostInstanceIdx = 0; - const inViewport = applyViewTransitionToHostInstances( - deletion.child, - name, - className, - null, - false, - ); - if (!inViewport) { - // Revert the transition names. This boundary is not in the viewport - // so we won't bother animating it. - restoreViewTransitionOnHostInstances(deletion.child, false); - // TODO: Should we still visit the children in case a named one was in the viewport? - } else if (pair !== undefined) { - // We found a new appearing view transition with the same name as this deletion. - // We'll transition between them instead of running the normal exit. - const oldinstance: ViewTransitionState = deletion.stateNode; - const newInstance: ViewTransitionState = pair; - newInstance.paired = oldinstance; - // Delete the entry so that we know when we've found all of them - // and can stop searching (size reaches zero). - // $FlowFixMe[incompatible-use]: Refined by the pair. - appearingViewTransitions.delete(name); - // Note: If the other side ends up outside the viewport, we'll still run this. - // Therefore it's possible for onShare to be called with only an old snapshot. - scheduleViewTransitionEvent(deletion, props.onShare); - } else { - scheduleViewTransitionEvent(deletion, props.onExit); - } - } - if (appearingViewTransitions !== null) { - // Look for more pairs deeper in the tree. - commitDeletedPairViewTransitions(deletion); - } - } else if ((deletion.subtreeFlags & ViewTransitionStatic) !== NoFlags) { - let child = deletion.child; - while (child !== null) { - commitExitViewTransitions(child); - child = child.sibling; - } - } else { - if (appearingViewTransitions !== null) { - commitDeletedPairViewTransitions(deletion); - } - } -} - -function commitBeforeUpdateViewTransition( - current: Fiber, - finishedWork: Fiber, -): void { - // The way we deal with multiple HostInstances as children of a View Transition in an - // update can get tricky. The important bit is that if you swap out n HostInstances - // from n HostInstances then they match up in order. Similarly, if you don't swap - // any HostInstances each instance just transitions as is. - // - // We call this function twice. First we apply the view transition names on the - // "current" tree in the snapshot phase. Then in the mutation phase we apply view - // transition names to the "finishedWork" tree. - // - // This means that if there were insertions or deletions before an updated Instance - // that same Instance might get different names in the "old" and the "new" state. - // For example if you swap two HostInstances inside a ViewTransition they don't - // animate to swap position but rather cross-fade into the other instance. This might - // be unexpected but it is in line with the semantics that the ViewTransition is its - // own layer that cross-fades its content when it updates. If you want to reorder then - // each child needs its own ViewTransition. - const oldProps: ViewTransitionProps = current.memoizedProps; - const oldName = getViewTransitionName(oldProps, current.stateNode); - const newProps: ViewTransitionProps = finishedWork.memoizedProps; - // This className applies only if there are fewer child DOM nodes than - // before or if this update should've been cancelled but we ended up with - // a parent animating so we need to animate the child too. - // For example, if update="foo" layout="none" and it turns out this was - // a layout only change, then the "foo" class will be applied even though - // it was not actually an update. Which is a bug. - let className: ?string = getViewTransitionClassName( - newProps.className, - newProps.update, - ); - if (className === 'none') { - className = getViewTransitionClassName(newProps.className, newProps.layout); - if (className === 'none') { - // If both update and layout are both "none" then we don't have to - // apply a name. Since we won't animate this boundary. - return; - } - } - viewTransitionHostInstanceIdx = 0; - applyViewTransitionToHostInstances( - current.child, - oldName, - className, - (current.memoizedState = []), - true, - ); -} - -function commitNestedViewTransitions(changedParent: Fiber): void { - let child = changedParent.child; - while (child !== null) { - if (child.tag === ViewTransitionComponent) { - // In this case the outer ViewTransition component wins but if there - // was an update through this component then the inner one wins. - const props: ViewTransitionProps = child.memoizedProps; - const name = getViewTransitionName(props, child.stateNode); - const className: ?string = getViewTransitionClassName( - props.className, - props.layout, - ); - if (className !== 'none') { - viewTransitionHostInstanceIdx = 0; - applyViewTransitionToHostInstances( - child.child, - name, - className, - (child.memoizedState = []), - false, - ); - } - } else if ((child.subtreeFlags & ViewTransitionStatic) !== NoFlags) { - commitNestedViewTransitions(child); - } - child = child.sibling; - } -} - -function restorePairedViewTransitions(parent: Fiber): void { - if ((parent.subtreeFlags & ViewTransitionNamedStatic) === NoFlags) { - // This has no named view transitions in its subtree. - return; - } - let child = parent.child; - while (child !== null) { - if (child.tag === OffscreenComponent && child.memoizedState === null) { - // This tree was already hidden so we skip it. - } else { - if ( - child.tag === ViewTransitionComponent && - (child.flags & ViewTransitionNamedStatic) !== NoFlags - ) { - const instance: ViewTransitionState = child.stateNode; - if (instance.paired !== null) { - instance.paired = null; - restoreViewTransitionOnHostInstances(child.child, false); - } - } - restorePairedViewTransitions(child); - } - child = child.sibling; - } -} - -function restoreEnterViewTransitions(placement: Fiber): void { - if (placement.tag === ViewTransitionComponent) { - const instance: ViewTransitionState = placement.stateNode; - instance.paired = null; - restoreViewTransitionOnHostInstances(placement.child, false); - restorePairedViewTransitions(placement); - } else if ((placement.subtreeFlags & ViewTransitionStatic) !== NoFlags) { - let child = placement.child; - while (child !== null) { - restoreEnterViewTransitions(child); - child = child.sibling; - } - } else { - restorePairedViewTransitions(placement); - } -} - -function restoreExitViewTransitions(deletion: Fiber): void { - if (deletion.tag === ViewTransitionComponent) { - const instance: ViewTransitionState = deletion.stateNode; - instance.paired = null; - restoreViewTransitionOnHostInstances(deletion.child, false); - restorePairedViewTransitions(deletion); - } else if ((deletion.subtreeFlags & ViewTransitionStatic) !== NoFlags) { - let child = deletion.child; - while (child !== null) { - restoreExitViewTransitions(child); - child = child.sibling; - } - } else { - restorePairedViewTransitions(deletion); - } -} - -function restoreUpdateViewTransition( - current: Fiber, - finishedWork: Fiber, -): void { - finishedWork.memoizedState = null; - restoreViewTransitionOnHostInstances(current.child, true); - restoreViewTransitionOnHostInstances(finishedWork.child, true); -} - -function restoreNestedViewTransitions(changedParent: Fiber): void { - let child = changedParent.child; - while (child !== null) { - if (child.tag === ViewTransitionComponent) { - child.memoizedState = null; - restoreViewTransitionOnHostInstances(child.child, false); - } else if ((child.subtreeFlags & ViewTransitionStatic) !== NoFlags) { - restoreNestedViewTransitions(child); - } - child = child.sibling; - } -} - -function cancelViewTransitionHostInstances( - currentViewTransition: Fiber, - child: null | Fiber, - stopAtNestedViewTransitions: boolean, -): void { - if (!supportsMutation) { - return; - } - while (child !== null) { - if (child.tag === HostComponent) { - const instance: Instance = child.stateNode; - const oldName = getViewTransitionName( - currentViewTransition.memoizedProps, - currentViewTransition.stateNode, - ); - if (viewTransitionCancelableChildren === null) { - viewTransitionCancelableChildren = []; - } - viewTransitionCancelableChildren.push( - instance, - oldName, - child.memoizedProps, - ); - viewTransitionHostInstanceIdx++; - } else if ( - child.tag === OffscreenComponent && - child.memoizedState !== null - ) { - // Skip any hidden subtrees. They were or are effectively not there. - } else if ( - child.tag === ViewTransitionComponent && - stopAtNestedViewTransitions - ) { - // Skip any nested view transitions for updates since in that case the - // inner most one is the one that handles the update. - } else { - cancelViewTransitionHostInstances( - currentViewTransition, - child.child, - stopAtNestedViewTransitions, - ); - } - child = child.sibling; - } -} - -function measureViewTransitionHostInstances( - currentViewTransition: Fiber, - parentViewTransition: Fiber, - child: null | Fiber, - name: string, - className: ?string, - previousMeasurements: null | Array, - stopAtNestedViewTransitions: boolean, -): boolean { - if (!supportsMutation) { - return true; - } - let inViewport = false; - while (child !== null) { - if (child.tag === HostComponent) { - const instance: Instance = child.stateNode; - if ( - previousMeasurements !== null && - viewTransitionHostInstanceIdx < previousMeasurements.length - ) { - // The previous measurement of the Instance in this location within the ViewTransition. - // Note that this might not be the same exact Instance if the Instances within the - // ViewTransition changed. - const previousMeasurement = - previousMeasurements[viewTransitionHostInstanceIdx]; - const nextMeasurement = measureInstance(instance); - if ( - wasInstanceInViewport(previousMeasurement) || - wasInstanceInViewport(nextMeasurement) - ) { - // If either the old or new state was within the viewport we have to animate this. - // But if it turns out that none of them were we'll be able to skip it. - inViewport = true; - } - if ( - (parentViewTransition.flags & Update) === NoFlags && - hasInstanceChanged(previousMeasurement, nextMeasurement) - ) { - parentViewTransition.flags |= Update; - } - if (hasInstanceAffectedParent(previousMeasurement, nextMeasurement)) { - // If this instance size within its parent has changed it might have caused the - // parent to relayout which needs a cross fade. - parentViewTransition.flags |= AffectedParentLayout; - } - } else { - // If there was an insertion of extra nodes, we have to assume they affected the parent. - // It should have already been marked as an Update due to the mutation. - parentViewTransition.flags |= AffectedParentLayout; - } - if ((parentViewTransition.flags & Update) !== NoFlags) { - // We might update this node so we need to apply its new name for the new state. - applyViewTransitionName( - instance, - viewTransitionHostInstanceIdx === 0 - ? name - : // If we have multiple Host Instances below, we add a suffix to the name to give - // each one a unique name. - name + '_' + viewTransitionHostInstanceIdx, - className, - ); - } - if (!inViewport || (parentViewTransition.flags & Update) === NoFlags) { - // It turns out that we had no other deeper mutations, the child transitions didn't - // affect the parent layout and this instance hasn't changed size. So we can skip - // animating it. However, in the current model this only works if the parent also - // doesn't animate. So we have to queue these and wait until we complete the parent - // to cancel them. - const oldName = getViewTransitionName( - currentViewTransition.memoizedProps, - currentViewTransition.stateNode, - ); - if (viewTransitionCancelableChildren === null) { - viewTransitionCancelableChildren = []; - } - viewTransitionCancelableChildren.push( - instance, - oldName, - child.memoizedProps, - ); - } - viewTransitionHostInstanceIdx++; - } else if ( - child.tag === OffscreenComponent && - child.memoizedState !== null - ) { - // Skip any hidden subtrees. They were or are effectively not there. - } else if ( - child.tag === ViewTransitionComponent && - stopAtNestedViewTransitions - ) { - // Skip any nested view transitions for updates since in that case the - // inner most one is the one that handles the update. - // If this inner boundary resized we need to bubble that information up. - parentViewTransition.flags |= child.flags & AffectedParentLayout; - } else { - if ( - measureViewTransitionHostInstances( - currentViewTransition, - parentViewTransition, - child.child, - name, - className, - previousMeasurements, - stopAtNestedViewTransitions, - ) - ) { - inViewport = true; - } - } - child = child.sibling; - } - return inViewport; -} - -function measureUpdateViewTransition( - current: Fiber, - finishedWork: Fiber, -): boolean { - const props: ViewTransitionProps = finishedWork.memoizedProps; - const updateClassName: ?string = getViewTransitionClassName( - props.className, - props.update, - ); - const layoutClassName: ?string = getViewTransitionClassName( - props.className, - props.layout, - ); - let className: ?string; - if (updateClassName === 'none') { - if (layoutClassName === 'none') { - // If both update and layout class name were none, then we didn't apply any - // names in the before update phase so we shouldn't now neither. - return false; - } - // We don't care if this is mutated or children layout changed, but we still - // measure each instance to see if it moved and therefore should apply layout. - finishedWork.flags &= ~Update; - className = layoutClassName; - } else if ((finishedWork.flags & Update) !== NoFlags) { - // It was updated and we have an appropriate class name to apply. - className = updateClassName; - } else { - if (layoutClassName === 'none') { - // If we did not update, then all changes are considered a layout. We'll - // attempt to cancel. - viewTransitionHostInstanceIdx = 0; - cancelViewTransitionHostInstances(current, finishedWork.child, true); - return false; - } - // We didn't update but we might still apply layout so we measure each - // instance to see if it moved or resized. - className = layoutClassName; - } - const name = getViewTransitionName(props, finishedWork.stateNode); - // If nothing changed due to a mutation, or children changing size - // and the measurements end up unchanged, we should restore it to not animate. - viewTransitionHostInstanceIdx = 0; - const previousMeasurements = current.memoizedState; - const inViewport = measureViewTransitionHostInstances( - current, - finishedWork, - finishedWork.child, - name, - className, - previousMeasurements, - true, - ); - const previousCount = - previousMeasurements === null ? 0 : previousMeasurements.length; - if (viewTransitionHostInstanceIdx !== previousCount) { - // If we found a different number of child DOM nodes we need to assume that - // the parent layout may have changed as a result. This is not necessarily - // true if those nodes were absolutely positioned. - finishedWork.flags |= AffectedParentLayout; - } - return inViewport; -} - -function measureNestedViewTransitions(changedParent: Fiber): void { - let child = changedParent.child; - while (child !== null) { - if (child.tag === ViewTransitionComponent) { - const current = child.alternate; - if (current !== null) { - const props: ViewTransitionProps = child.memoizedProps; - const name = getViewTransitionName(props, child.stateNode); - const className: ?string = getViewTransitionClassName( - props.className, - props.layout, - ); - viewTransitionHostInstanceIdx = 0; - const inViewport = measureViewTransitionHostInstances( - current, - child, - child.child, - name, - className, - child.memoizedState, - false, - ); - if ((child.flags & Update) === NoFlags || !inViewport) { - // Nothing changed. - } else { - scheduleViewTransitionEvent(child, props.onLayout); - } - } - } else if ((child.subtreeFlags & ViewTransitionStatic) !== NoFlags) { - measureNestedViewTransitions(child); - } - child = child.sibling; - } -} - function commitLayoutEffectOnFiber( finishedRoot: FiberRoot, current: Fiber | null, @@ -3204,14 +2446,14 @@ function commitAfterMutationEffectsOnFiber( switch (finishedWork.tag) { case HostRoot: { viewTransitionContextChanged = false; - viewTransitionCancelableChildren = null; + setViewTransitionCancelableChildren(null); recursivelyTraverseAfterMutationEffects(root, finishedWork, lanes); if (!viewTransitionContextChanged) { // If we didn't leak any resizing out to the root, we don't have to transition // the root itself. This means that we can now safely cancel any cancellations // that bubbled all the way up. const cancelableChildren = viewTransitionCancelableChildren; - viewTransitionCancelableChildren = null; + setViewTransitionCancelableChildren(null); if (cancelableChildren !== null) { for (let i = 0; i < cancelableChildren.length; i += 3) { cancelViewTransitionName( @@ -3264,7 +2506,7 @@ function commitAfterMutationEffectsOnFiber( const prevContextChanged = viewTransitionContextChanged; const prevCancelableChildren = viewTransitionCancelableChildren; viewTransitionContextChanged = false; - viewTransitionCancelableChildren = null; + setViewTransitionCancelableChildren(null); recursivelyTraverseAfterMutationEffects(root, finishedWork, lanes); if (viewTransitionContextChanged) { @@ -3287,7 +2529,7 @@ function commitAfterMutationEffectsOnFiber( prevCancelableChildren, viewTransitionCancelableChildren, ); - viewTransitionCancelableChildren = prevCancelableChildren; + setViewTransitionCancelableChildren(prevCancelableChildren); } // TODO: If this doesn't end up canceled, because a parent animates, // then we should probably issue an event since this instance is part of it. @@ -3301,7 +2543,7 @@ function commitAfterMutationEffectsOnFiber( ); // If this boundary did update, we cannot cancel its children so those are dropped. - viewTransitionCancelableChildren = prevCancelableChildren; + setViewTransitionCancelableChildren(prevCancelableChildren); } if ((finishedWork.flags & AffectedParentLayout) !== NoFlags) { @@ -4810,7 +4052,7 @@ export function commitPassiveUnmountEffects(finishedWork: Fiber): void { // pairs. let suspenseyCommitFlag = ShouldSuspendCommit; export function accumulateSuspenseyCommit(finishedWork: Fiber): void { - appearingViewTransitions = null; + resetAppearingViewTransitions(); accumulateSuspenseyCommitOnFiber(finishedWork); } @@ -4897,14 +4139,11 @@ function accumulateSuspenseyCommitOnFiber(fiber: Fiber) { if (name != null && name !== 'auto') { // This is a named ViewTransition being mounted or reappearing. Let's add it to // the map so we can match it with deletions later. - if (appearingViewTransitions === null) { - appearingViewTransitions = new Map(); - } + const state: ViewTransitionState = fiber.stateNode; // Reset the pair in case we didn't end up restoring the instance in previous commits. // This shouldn't really happen anymore but just in case. We could maybe add an invariant. - const instance: ViewTransitionState = fiber.stateNode; - instance.paired = null; - appearingViewTransitions.set(name, instance); + state.paired = null; + trackAppearingViewTransition(name, state); } } recursivelyAccumulateSuspenseyCommit(fiber); diff --git a/packages/react-reconciler/src/ReactFiberConfigWithNoMutation.js b/packages/react-reconciler/src/ReactFiberConfigWithNoMutation.js index da34b26084de5..430ad02abc1b1 100644 --- a/packages/react-reconciler/src/ReactFiberConfigWithNoMutation.js +++ b/packages/react-reconciler/src/ReactFiberConfigWithNoMutation.js @@ -46,6 +46,9 @@ export const wasInstanceInViewport = shim; export const hasInstanceChanged = shim; export const hasInstanceAffectedParent = shim; export const startViewTransition = shim; +export type RunningGestureTransition = null; +export const startGestureTransition = shim; +export const stopGestureTransition = shim; export type ViewTransitionInstance = null | {name: string, ...}; export const createViewTransitionInstance = shim; export type GestureTimeline = any; diff --git a/packages/react-reconciler/src/ReactFiberGestureScheduler.js b/packages/react-reconciler/src/ReactFiberGestureScheduler.js index fffb7d524d9e4..33d477f07daec 100644 --- a/packages/react-reconciler/src/ReactFiberGestureScheduler.js +++ b/packages/react-reconciler/src/ReactFiberGestureScheduler.js @@ -8,11 +8,21 @@ */ import type {FiberRoot} from './ReactInternalTypes'; -import type {GestureTimeline} from './ReactFiberConfig'; +import type { + GestureTimeline, + RunningGestureTransition, +} from './ReactFiberConfig'; -import {GestureLane} from './ReactFiberLane'; +import { + GestureLane, + includesBlockingLane, + includesTransitionLane, +} from './ReactFiberLane'; import {ensureRootIsScheduled} from './ReactFiberRootScheduler'; -import {subscribeToGestureDirection} from './ReactFiberConfig'; +import { + subscribeToGestureDirection, + stopGestureTransition, +} from './ReactFiberConfig'; // This type keeps track of any scheduled or active gestures. export type ScheduledGesture = { @@ -23,6 +33,7 @@ export type ScheduledGesture = { rangeCurrent: number, // The starting offset along the timeline. rangeNext: number, // The end along the timeline where the next state is reached. cancel: () => void, // Cancel the subscription to direction change. + running: null | RunningGestureTransition, // Used to cancel the running transition after we're done. prev: null | ScheduledGesture, // The previous scheduled gesture in the queue for this root. next: null | ScheduledGesture, // The next scheduled gesture in the queue for this root. }; @@ -35,7 +46,7 @@ export function scheduleGesture( rangeCurrent: number, rangeNext: number, ): ScheduledGesture { - let prev = root.gestures; + let prev = root.pendingGestures; while (prev !== null) { if (prev.provider === provider) { // Existing instance found. @@ -59,16 +70,16 @@ export function scheduleGesture( } if (gesture.direction !== direction) { gesture.direction = direction; - if (gesture.prev === null && root.gestures !== gesture) { + if (gesture.prev === null && root.pendingGestures !== gesture) { // This gesture is not in the schedule, meaning it was already rendered. // We need to rerender in the new direction. Insert it into the first slot // in case other gestures are queued after the on-going one. - const existing = root.gestures; + const existing = root.pendingGestures; gesture.next = existing; if (existing !== null) { existing.prev = gesture; } - root.gestures = gesture; + root.pendingGestures = gesture; // Schedule the lane on the root. The Fibers will already be marked as // long as the gesture is active on that Hook. root.pendingLanes |= GestureLane; @@ -86,11 +97,12 @@ export function scheduleGesture( rangeCurrent: rangeCurrent, rangeNext: rangeNext, cancel: cancel, + running: null, prev: prev, next: null, }; if (prev === null) { - root.gestures = gesture; + root.pendingGestures = gesture; } else { prev.next = gesture; } @@ -106,10 +118,35 @@ export function cancelScheduledGesture( if (gesture.count === 0) { const cancelDirectionSubscription = gesture.cancel; cancelDirectionSubscription(); - // Delete the scheduled gesture from the queue. + // Delete the scheduled gesture from the pending queue. deleteScheduledGesture(root, gesture); // TODO: If we're currently rendering this gesture, we need to restart the render // on a different gesture or cancel the render.. + // TODO: We might want to pause the View Transition at this point since you should + // no longer be able to update the position of anything but it might be better to + // just commit the gesture state. + const runningTransition = gesture.running; + if (runningTransition !== null) { + const pendingLanesExcludingGestureLane = root.pendingLanes & ~GestureLane; + if ( + includesBlockingLane(pendingLanesExcludingGestureLane) || + includesTransitionLane(pendingLanesExcludingGestureLane) + ) { + // If we have pending work we schedule the gesture to be stopped at the next commit. + // This ensures that we don't snap back to the previous state until we have + // had a chance to commit any resulting updates. + const existing = root.stoppingGestures; + if (existing !== null) { + gesture.next = existing; + existing.prev = gesture; + } + root.stoppingGestures = gesture; + } else { + gesture.running = null; + // If there's no work scheduled so we can stop the View Transition right away. + stopGestureTransition(runningTransition); + } + } } } @@ -118,15 +155,19 @@ export function deleteScheduledGesture( gesture: ScheduledGesture, ): void { if (gesture.prev === null) { - if (root.gestures === gesture) { - root.gestures = gesture.next; - if (root.gestures === null) { + if (root.pendingGestures === gesture) { + root.pendingGestures = gesture.next; + if (root.pendingGestures === null) { // Gestures don't clear their lanes while the gesture is still active but it // might not be scheduled to do any more renders and so we shouldn't schedule // any more gesture lane work until a new gesture is scheduled. root.pendingLanes &= ~GestureLane; } } + if (root.stoppingGestures === gesture) { + // This should not really happen the way we use it now but just in case we start. + root.stoppingGestures = gesture.next; + } } else { gesture.prev.next = gesture.next; if (gesture.next !== null) { @@ -136,3 +177,18 @@ export function deleteScheduledGesture( gesture.next = null; } } + +export function stopCompletedGestures(root: FiberRoot) { + let gesture = root.stoppingGestures; + root.stoppingGestures = null; + while (gesture !== null) { + if (gesture.running !== null) { + stopGestureTransition(gesture.running); + gesture.running = null; + } + const nextGesture = gesture.next; + gesture.next = null; + gesture.prev = null; + gesture = nextGesture; + } +} diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js index ddf051bcdb94f..270cd87d4941c 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.js +++ b/packages/react-reconciler/src/ReactFiberHooks.js @@ -3595,7 +3595,7 @@ function mountId(): string { const treeId = getTreeId(); // Use a captial R prefix for server-generated ids. - id = ':' + identifierPrefix + 'R' + treeId; + id = '\u00AB' + identifierPrefix + 'R' + treeId; // Unless this is the first id at this level, append a number at the end // that represents the position of this useId hook among all the useId @@ -3605,11 +3605,16 @@ function mountId(): string { id += 'H' + localId.toString(32); } - id += ':'; + id += '\u00BB'; } else { // Use a lowercase r prefix for client-generated ids. const globalClientId = globalClientIdCounter++; - id = ':' + identifierPrefix + 'r' + globalClientId.toString(32) + ':'; + id = + '\u00AB' + + identifierPrefix + + 'r' + + globalClientId.toString(32) + + '\u00BB'; } hook.memoizedState = id; @@ -4121,7 +4126,7 @@ function updateSwipeTransition( ); } // We assume that the currently rendering gesture is the one first in the queue. - const rootRenderGesture = root.gestures; + const rootRenderGesture = root.pendingGestures; if (rootRenderGesture !== null) { let update = queue.pending; while (update !== null) { diff --git a/packages/react-reconciler/src/ReactFiberRoot.js b/packages/react-reconciler/src/ReactFiberRoot.js index 03ddde7a5ab5b..41401bac2bd8f 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.js +++ b/packages/react-reconciler/src/ReactFiberRoot.js @@ -99,7 +99,8 @@ function FiberRootNode( this.formState = formState; if (enableSwipeTransition) { - this.gestures = null; + this.pendingGestures = null; + this.stoppingGestures = null; } this.incompleteTransitions = new Map(); diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index b3d1e5371c06c..bf611f73275a7 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -100,6 +100,7 @@ import { resolveUpdatePriority, trackSchedulerEvent, startViewTransition, + startGestureTransition, createViewTransitionInstance, } from './ReactFiberConfig'; @@ -226,8 +227,13 @@ import { invokeLayoutEffectUnmountInDEV, invokePassiveEffectUnmountInDEV, accumulateSuspenseyCommit, - shouldStartViewTransition, } from './ReactFiberCommitWork'; +import {shouldStartViewTransition} from './ReactFiberCommitViewTransitions'; +import { + insertDestinationClones, + applyDepartureTransitions, + startGestureAnimations, +} from './ReactFiberApplyGesture'; import {enqueueUpdate} from './ReactFiberClassUpdateQueue'; import {resetContextDependencies} from './ReactFiberNewContext'; import { @@ -341,7 +347,10 @@ import { import {getMaskedContext, getUnmaskedContext} from './ReactFiberContext'; import {peekEntangledActionLane} from './ReactFiberAsyncAction'; import {logUncaughtError} from './ReactFiberErrorLogger'; -import {deleteScheduledGesture} from './ReactFiberGestureScheduler'; +import { + deleteScheduledGesture, + stopCompletedGestures, +} from './ReactFiberGestureScheduler'; const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; @@ -644,7 +653,9 @@ const PENDING_LAYOUT_PHASE = 2; const PENDING_AFTER_MUTATION_PHASE = 3; const PENDING_SPAWNED_WORK = 4; const PENDING_PASSIVE_PHASE = 5; -let pendingEffectsStatus: 0 | 1 | 2 | 3 | 4 | 5 = 0; +const PENDING_GESTURE_MUTATION_PHASE = 6; +const PENDING_GESTURE_ANIMATION_PHASE = 7; +let pendingEffectsStatus: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 = 0; let pendingEffectsRoot: FiberRoot = (null: any); let pendingFinishedWork: Fiber = (null: any); let pendingEffectsLanes: Lanes = NoLanes; @@ -1424,11 +1435,12 @@ function commitRootWhenReady( const subtreeFlags = finishedWork.subtreeFlags; const isViewTransitionEligible = enableViewTransition && includesOnlyViewTransitionEligibleLanes(lanes); // TODO: Use a subtreeFlag to optimize. + const isGestureTransition = enableSwipeTransition && isGestureRender(lanes); const maySuspendCommit = subtreeFlags & ShouldSuspendCommit || (subtreeFlags & BothVisibilityAndMaySuspendCommit) === BothVisibilityAndMaySuspendCommit; - if (isViewTransitionEligible || maySuspendCommit) { + if (isViewTransitionEligible || maySuspendCommit || isGestureTransition) { // Before committing, ask the renderer whether the host tree is ready. // If it's not, we'll wait until it notifies us. startSuspendingCommit(); @@ -1439,8 +1451,12 @@ function commitRootWhenReady( // This will also track any newly added or appearing ViewTransition // components for the purposes of forming pairs. accumulateSuspenseyCommit(finishedWork); - if (isViewTransitionEligible) { - suspendOnActiveViewTransition(root.containerInfo); + if (isViewTransitionEligible || isGestureTransition) { + // If we're stopping gestures we don't have to wait for any pending + // view transition. We'll stop it when we commit. + if (!enableSwipeTransition || root.stoppingGestures === null) { + suspendOnActiveViewTransition(root.containerInfo); + } } // At the end, ask the renderer if it's ready to commit, or if we should // suspend. If it's not ready, it will return a callback to subscribe to @@ -3263,6 +3279,12 @@ function commitRoot( if (enableSchedulingProfiler) { markCommitStopped(); } + if (enableSwipeTransition) { + // Stop any gestures that were completed and is now being reverted. + if (root.stoppingGestures !== null) { + stopCompletedGestures(root); + } + } return; } else { if (__DEV__) { @@ -3291,7 +3313,7 @@ function commitRoot( const concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes(); remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes); - if (enableSwipeTransition && root.gestures === null) { + if (enableSwipeTransition && root.pendingGestures === null) { // Gestures don't clear their lanes while the gesture is still active but it // might not be scheduled to do any more renders and so we shouldn't schedule // any more gesture lane work until a new gesture is scheduled. @@ -3321,21 +3343,6 @@ function commitRoot( // times out. } - if (enableSwipeTransition && isGestureRender(lanes)) { - // This is a special kind of render that doesn't commit regular effects. - commitGestureOnRoot( - root, - finishedWork, - recoverableErrors, - enableProfilerTimer - ? suspendedCommitReason === IMMEDIATE_COMMIT - ? completedRenderEndTime - : commitStartTime - : 0, - ); - return; - } - // workInProgressX might be overwritten, so we want // to store it in pendingPassiveX until they get processed // We need to pass this through as an argument to commitRoot @@ -3354,6 +3361,21 @@ function commitRoot( pendingSuspendedCommitReason = suspendedCommitReason; } + if (enableSwipeTransition && isGestureRender(lanes)) { + // This is a special kind of render that doesn't commit regular effects. + commitGestureOnRoot( + root, + finishedWork, + recoverableErrors, + enableProfilerTimer + ? suspendedCommitReason === IMMEDIATE_COMMIT + ? completedRenderEndTime + : commitStartTime + : 0, + ); + return; + } + // If there are pending passive effects, schedule a callback to process them. // Do this as early as possible, so it is queued before anything else that // might get scheduled in the commit phase. (See #16714.) @@ -3461,10 +3483,23 @@ function commitRoot( ReactSharedInternals.T = prevTransition; } } + + let willStartViewTransition = shouldStartViewTransition; + if (enableSwipeTransition) { + // Stop any gestures that were completed and is now being committed. + if (root.stoppingGestures !== null) { + stopCompletedGestures(root); + // If we are in the process of stopping some gesture we shouldn't start + // a View Transition because that would start from the previous state to + // the next state. + willStartViewTransition = false; + } + } + pendingEffectsStatus = PENDING_MUTATION_PHASE; const startedViewTransition = enableViewTransition && - shouldStartViewTransition && + willStartViewTransition && startViewTransition( root.containerInfo, pendingTransitionTypes, @@ -3633,6 +3668,7 @@ function flushSpawnedWork(): void { } else { pendingEffectsStatus = NO_PENDING_EFFECTS; pendingEffectsRoot = (null: any); // Clear for GC purposes. + pendingFinishedWork = (null: any); // Clear for GC purposes. // There were no passive effects, so we can immediately release the cache // pool for this render. releaseRootPooledCache(root, root.pendingLanes); @@ -3830,20 +3866,103 @@ function flushSpawnedWork(): void { function commitGestureOnRoot( root: FiberRoot, - finishedWork: null | Fiber, + finishedWork: Fiber, recoverableErrors: null | Array>, renderEndTime: number, // Profiling-only ): void { // We assume that the gesture we just rendered was the first one in the queue. - const finishedGesture = root.gestures; + const finishedGesture = root.pendingGestures; if (finishedGesture === null) { - throw new Error( - 'Finished rendering the gesture lane but there were no pending gestures. ' + - 'React should not have started a render in this case. This is a bug in React.', - ); + // We must have already cancelled this gesture before we had a chance to + // render it. Let's schedule work on the next set of lanes. + ensureRootIsScheduled(root); + return; } deleteScheduledGesture(root, finishedGesture); - // TODO: Run the gesture + + const prevTransition = ReactSharedInternals.T; + ReactSharedInternals.T = null; + const previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(DiscreteEventPriority); + const prevExecutionContext = executionContext; + executionContext |= CommitContext; + try { + insertDestinationClones(root, finishedWork); + } finally { + // Reset the priority to the previous non-sync value. + executionContext = prevExecutionContext; + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = prevTransition; + } + // TODO: Collect transition types. + pendingTransitionTypes = null; + pendingEffectsStatus = PENDING_GESTURE_MUTATION_PHASE; + + finishedGesture.running = startGestureTransition( + root.containerInfo, + pendingTransitionTypes, + flushGestureMutations, + flushGestureAnimations, + ); +} + +function flushGestureMutations(): void { + if (pendingEffectsStatus !== PENDING_GESTURE_MUTATION_PHASE) { + return; + } + pendingEffectsStatus = NO_PENDING_EFFECTS; + const root = pendingEffectsRoot; + const finishedWork = pendingFinishedWork; + + const prevTransition = ReactSharedInternals.T; + ReactSharedInternals.T = null; + const previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(DiscreteEventPriority); + const prevExecutionContext = executionContext; + executionContext |= CommitContext; + try { + applyDepartureTransitions(root, finishedWork); + } finally { + // Reset the priority to the previous non-sync value. + executionContext = prevExecutionContext; + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = prevTransition; + } + + pendingEffectsStatus = PENDING_GESTURE_ANIMATION_PHASE; +} + +function flushGestureAnimations(): void { + // If we get canceled before we start we might not have applied + // mutations yet. We need to apply them first. + flushGestureMutations(); + if (pendingEffectsStatus !== PENDING_GESTURE_ANIMATION_PHASE) { + return; + } + pendingEffectsStatus = NO_PENDING_EFFECTS; + const root = pendingEffectsRoot; + const finishedWork = pendingFinishedWork; + pendingEffectsRoot = (null: any); // Clear for GC purposes. + pendingFinishedWork = (null: any); // Clear for GC purposes. + pendingEffectsLanes = NoLanes; + + const prevTransition = ReactSharedInternals.T; + ReactSharedInternals.T = null; + const previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(DiscreteEventPriority); + const prevExecutionContext = executionContext; + executionContext |= CommitContext; + try { + startGestureAnimations(root, finishedWork); + } finally { + // Reset the priority to the previous non-sync value. + executionContext = prevExecutionContext; + setCurrentUpdatePriority(previousPriority); + ReactSharedInternals.T = prevTransition; + } + + // Now that we've rendered this lane. Start working on the next lane. + ensureRootIsScheduled(root); } function makeErrorInfo(componentStack: ?string) { @@ -3879,6 +3998,8 @@ function releaseRootPooledCache(root: FiberRoot, remainingLanes: Lanes) { export function flushPendingEffects(wasDelayedCommit?: boolean): boolean { // Returns whether passive effects were flushed. + flushGestureMutations(); + flushGestureAnimations(); flushMutationEffects(); flushLayoutEffects(); // Skip flushAfterMutation if we're forcing this early. @@ -3932,6 +4053,7 @@ function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) { const lanes = pendingEffectsLanes; pendingEffectsStatus = NO_PENDING_EFFECTS; pendingEffectsRoot = (null: any); // Clear for GC purposes. + pendingFinishedWork = (null: any); // Clear for GC purposes. // TODO: This is sometimes out of sync with pendingEffectsRoot. // Figure out why and fix it. It's not causing any known issues (probably // because it's only used for profiling), but it's a refactor hazard. diff --git a/packages/react-reconciler/src/ReactInternalTypes.js b/packages/react-reconciler/src/ReactInternalTypes.js index 3479eba1b9dd3..be5e9a5c0da69 100644 --- a/packages/react-reconciler/src/ReactInternalTypes.js +++ b/packages/react-reconciler/src/ReactInternalTypes.js @@ -284,7 +284,8 @@ type BaseFiberRootProperties = { formState: ReactFormState | null, // enableSwipeTransition only - gestures: null | ScheduledGesture, + pendingGestures: null | ScheduledGesture, + stoppingGestures: null | ScheduledGesture, }; // The following attributes are only used by DevTools and are only present in DEV builds. diff --git a/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js b/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js index 6b2781c0ab2a5..9569b4a896cee 100644 --- a/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js +++ b/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js @@ -40,6 +40,7 @@ export opaque type NoTimeout = mixed; export opaque type RendererInspectionConfig = mixed; export opaque type TransitionStatus = mixed; export opaque type FormInstance = mixed; +export type RunningGestureTransition = mixed; export type ViewTransitionInstance = null | {name: string, ...}; export opaque type InstanceMeasurement = mixed; export type EventResponder = any; @@ -145,6 +146,8 @@ export const wasInstanceInViewport = $$$config.wasInstanceInViewport; export const hasInstanceChanged = $$$config.hasInstanceChanged; export const hasInstanceAffectedParent = $$$config.hasInstanceAffectedParent; export const startViewTransition = $$$config.startViewTransition; +export const startGestureTransition = $$$config.startGestureTransition; +export const stopGestureTransition = $$$config.stopGestureTransition; export const getCurrentGestureOffset = $$$config.getCurrentGestureOffset; export const subscribeToGestureDirection = $$$config.subscribeToGestureDirection; diff --git a/packages/react-test-renderer/src/ReactFiberConfigTestHost.js b/packages/react-test-renderer/src/ReactFiberConfigTestHost.js index 8f4f81cabb9ce..48939e9ff45ad 100644 --- a/packages/react-test-renderer/src/ReactFiberConfigTestHost.js +++ b/packages/react-test-renderer/src/ReactFiberConfigTestHost.js @@ -375,6 +375,21 @@ export function startViewTransition( return false; } +export type RunningGestureTransition = null; + +export function startGestureTransition( + rootContainer: Container, + transitionTypes: null | TransitionTypes, + mutationCallback: () => void, + animateCallback: () => void, +): RunningGestureTransition { + mutationCallback(); + animateCallback(); + return null; +} + +export function stopGestureTransition(transition: RunningGestureTransition) {} + export type ViewTransitionInstance = null | {name: string, ...}; export function createViewTransitionInstance( diff --git a/scripts/release/prepare-release-from-npm-commands/confirm-stable-version-numbers.js b/scripts/release/prepare-release-from-npm-commands/confirm-stable-version-numbers.js index 0b93fba2fc12b..6bf49132149a8 100644 --- a/scripts/release/prepare-release-from-npm-commands/confirm-stable-version-numbers.js +++ b/scripts/release/prepare-release-from-npm-commands/confirm-stable-version-numbers.js @@ -7,7 +7,7 @@ const semver = require('semver'); const theme = require('../theme'); const {confirm} = require('../utils'); -const run = async ({skipPackages}, versionsMap) => { +const run = async ({ci, skipPackages}, versionsMap) => { const groupedVersionsMap = new Map(); // Group packages with the same source versions. @@ -22,44 +22,46 @@ const run = async ({skipPackages}, versionsMap) => { } }); - // Prompt user to confirm or override each version group. - const entries = [...groupedVersionsMap.entries()]; - for (let i = 0; i < entries.length; i++) { - const [bestGuessVersion, packages] = entries[i]; - const packageNames = packages.map(name => theme.package(name)).join(', '); + if (ci !== true) { + // Prompt user to confirm or override each version group if not running in CI. + const entries = [...groupedVersionsMap.entries()]; + for (let i = 0; i < entries.length; i++) { + const [bestGuessVersion, packages] = entries[i]; + const packageNames = packages.map(name => theme.package(name)).join(', '); - let version = bestGuessVersion; - if ( - skipPackages.some(skipPackageName => packages.includes(skipPackageName)) - ) { - await confirm( - theme`{spinnerSuccess ✓} Version for ${packageNames} will remain {version ${bestGuessVersion}}` - ); - } else { - const defaultVersion = bestGuessVersion - ? theme.version(` (default ${bestGuessVersion})`) - : ''; - version = - (await prompt( - theme`{spinnerSuccess ✓} Version for ${packageNames}${defaultVersion}: ` - )) || bestGuessVersion; - prompt.done(); - } + let version = bestGuessVersion; + if ( + skipPackages.some(skipPackageName => packages.includes(skipPackageName)) + ) { + await confirm( + theme`{spinnerSuccess ✓} Version for ${packageNames} will remain {version ${bestGuessVersion}}` + ); + } else { + const defaultVersion = bestGuessVersion + ? theme.version(` (default ${bestGuessVersion})`) + : ''; + version = + (await prompt( + theme`{spinnerSuccess ✓} Version for ${packageNames}${defaultVersion}: ` + )) || bestGuessVersion; + prompt.done(); + } - // Verify a valid version has been supplied. - try { - semver(version); + // Verify a valid version has been supplied. + try { + semver(version); - packages.forEach(packageName => { - versionsMap.set(packageName, version); - }); - } catch (error) { - console.log( - theme`{spinnerError ✘} Version {version ${version}} is invalid.` - ); + packages.forEach(packageName => { + versionsMap.set(packageName, version); + }); + } catch (error) { + console.log( + theme`{spinnerError ✘} Version {version ${version}} is invalid.` + ); - // Prompt again - i--; + // Prompt again + i--; + } } } }; diff --git a/scripts/release/prepare-release-from-npm-commands/guess-stable-version-numbers.js b/scripts/release/prepare-release-from-npm-commands/guess-stable-version-numbers.js index a3cde5d1c4fce..c0072b6637177 100644 --- a/scripts/release/prepare-release-from-npm-commands/guess-stable-version-numbers.js +++ b/scripts/release/prepare-release-from-npm-commands/guess-stable-version-numbers.js @@ -5,7 +5,10 @@ const semver = require('semver'); const {execRead, logPromise} = require('../utils'); -const run = async ({cwd, packages, skipPackages}, versionsMap) => { +const run = async ( + {cwd, packages, skipPackages, ci, publishVersion}, + versionsMap +) => { const branch = await execRead('git branch | grep \\* | cut -d " " -f2', { cwd, }); @@ -13,30 +16,41 @@ const run = async ({cwd, packages, skipPackages}, versionsMap) => { for (let i = 0; i < packages.length; i++) { const packageName = packages[i]; - try { - // In case local package JSONs are outdated, - // guess the next version based on the latest NPM release. - const version = await execRead(`npm show ${packageName} version`); - - if (skipPackages.includes(packageName)) { - versionsMap.set(packageName, version); + if (ci === true) { + if (publishVersion != null) { + versionsMap.set(packageName, publishVersion); } else { - const {major, minor, patch} = semver(version); - - // Guess the next version by incrementing patch. - // The script will confirm this later. - // By default, new releases from mains should increment the minor version number, - // and patch releases should be done from branches. - if (branch === 'main') { - versionsMap.set(packageName, `${major}.${minor + 1}.0`); + console.error( + 'When running in CI mode, a publishVersion must be supplied' + ); + process.exit(1); + } + } else { + try { + // In case local package JSONs are outdated, + // guess the next version based on the latest NPM release. + const version = await execRead(`npm show ${packageName} version`); + + if (skipPackages.includes(packageName)) { + versionsMap.set(packageName, version); } else { - versionsMap.set(packageName, `${major}.${minor}.${patch + 1}`); + const {major, minor, patch} = semver(version); + + // Guess the next version by incrementing patch. + // The script will confirm this later. + // By default, new releases from mains should increment the minor version number, + // and patch releases should be done from branches. + if (branch === 'main') { + versionsMap.set(packageName, `${major}.${minor + 1}.0`); + } else { + versionsMap.set(packageName, `${major}.${minor}.${patch + 1}`); + } } + } catch (error) { + // If the package has not yet been published, + // we'll require a version number to be entered later. + versionsMap.set(packageName, null); } - } catch (error) { - // If the package has not yet been published, - // we'll require a version number to be entered later. - versionsMap.set(packageName, null); } } }; diff --git a/scripts/release/prepare-release-from-npm-commands/parse-params.js b/scripts/release/prepare-release-from-npm-commands/parse-params.js index b9aa1a4f5e7e8..ef9c4979b2030 100644 --- a/scripts/release/prepare-release-from-npm-commands/parse-params.js +++ b/scripts/release/prepare-release-from-npm-commands/parse-params.js @@ -13,6 +13,13 @@ const paramDefinitions = [ 'Skip NPM and use the build already present in "build/node_modules".', defaultValue: false, }, + { + name: 'onlyPackages', + type: String, + multiple: true, + description: 'Packages to include in publishing', + defaultValue: [], + }, { name: 'skipPackages', type: String, @@ -32,6 +39,17 @@ const paramDefinitions = [ description: 'Version of published "next" release (e.g. 0.0.0-0e526bcec-20210202)', }, + { + name: 'publishVersion', + type: String, + description: 'Version to publish', + }, + { + name: 'ci', + type: Boolean, + description: 'Run in automated environment, without interactive prompts.', + defaultValue: false, + }, ]; module.exports = () => { diff --git a/scripts/release/prepare-release-from-npm-commands/update-stable-version-numbers.js b/scripts/release/prepare-release-from-npm-commands/update-stable-version-numbers.js index a41d83ac69dbb..f201118890456 100644 --- a/scripts/release/prepare-release-from-npm-commands/update-stable-version-numbers.js +++ b/scripts/release/prepare-release-from-npm-commands/update-stable-version-numbers.js @@ -9,7 +9,7 @@ const {join, relative} = require('path'); const {confirm, execRead, printDiff} = require('../utils'); const theme = require('../theme'); -const run = async ({cwd, packages, version}, versionsMap) => { +const run = async ({cwd, packages, version, ci}, versionsMap) => { const nodeModulesPath = join(cwd, 'build/node_modules'); // Cache all package JSONs for easy lookup below. @@ -107,7 +107,9 @@ const run = async ({cwd, packages, version}, versionsMap) => { printDependencies(packageJSON.dependencies, 'dependency'); printDependencies(packageJSON.peerDependencies, 'peer'); } - await confirm('Do the versions above look correct?'); + if (ci !== true) { + await confirm('Do the versions above look correct?'); + } clear(); @@ -167,7 +169,9 @@ const run = async ({cwd, packages, version}, versionsMap) => { console.log( theme`A full diff is available at {path ${relative(cwd, diffPath)}}.` ); - await confirm('Do the changes above look correct?'); + if (ci !== true) { + await confirm('Do the changes above look correct?'); + } } else { console.log( theme`Skipping React renderer version update because React is not included in the release.` diff --git a/scripts/release/prepare-release-from-npm.js b/scripts/release/prepare-release-from-npm.js index e23ffb39bc1c0..bb67fddd37803 100755 --- a/scripts/release/prepare-release-from-npm.js +++ b/scripts/release/prepare-release-from-npm.js @@ -26,8 +26,18 @@ const run = async () => { params.version = await getLatestNextVersion(); } + if (params.onlyPackages.length > 0 && params.skipPackages.length > 0) { + console.error( + '--onlyPackages and --skipPackages cannot be used together' + ); + process.exit(1); + } + params.packages = await getPublicPackages(isExperimental); params.packages = params.packages.filter(packageName => { + if (params.onlyPackages.length > 0) { + return params.onlyPackages.includes(packageName); + } return !params.skipPackages.includes(packageName); }); diff --git a/scripts/release/publish-commands/confirm-version-and-tags.js b/scripts/release/publish-commands/confirm-version-and-tags.js index 6900878da02f6..2c6fed58d1937 100644 --- a/scripts/release/publish-commands/confirm-version-and-tags.js +++ b/scripts/release/publish-commands/confirm-version-and-tags.js @@ -38,6 +38,9 @@ const run = async ({cwd, packages, tags, ci}) => { console.log( theme`• {package ${packageName}} {version ${packageJSON.version}}` ); + if (ci) { + console.log(packageJSON); + } } if (!ci) { diff --git a/scripts/release/publish-commands/parse-params.js b/scripts/release/publish-commands/parse-params.js index b7196447d4da8..ce9a9b7825c1a 100644 --- a/scripts/release/publish-commands/parse-params.js +++ b/scripts/release/publish-commands/parse-params.js @@ -19,6 +19,13 @@ const paramDefinitions = [ description: 'NPM tags to point to the new release.', defaultValue: ['untagged'], }, + { + name: 'onlyPackages', + type: String, + multiple: true, + description: 'Packages to include in publishing', + defaultValue: [], + }, { name: 'skipPackages', type: String, @@ -32,6 +39,11 @@ const paramDefinitions = [ description: 'Run in automated environment, without interactive prompts.', defaultValue: false, }, + { + name: 'publishVersion', + type: String, + description: 'Version to publish', + }, ]; module.exports = () => { diff --git a/scripts/release/publish-commands/publish-to-npm.js b/scripts/release/publish-commands/publish-to-npm.js index d9e3b1902383f..f1e62657c0c38 100644 --- a/scripts/release/publish-commands/publish-to-npm.js +++ b/scripts/release/publish-commands/publish-to-npm.js @@ -27,7 +27,9 @@ const run = async ({cwd, dry, tags, ci}, packageName, otp) => { await confirm('Is this expected?'); } } else { - console.log(theme`{spinnerSuccess ✓} Publishing {package ${packageName}}`); + console.log( + theme`{spinnerSuccess ✓} Publishing {package ${packageName}}${dry ? ' (dry-run)' : ''}` + ); // Publish the package and tag it. if (!dry) { diff --git a/scripts/release/publish.js b/scripts/release/publish.js index dcd31f1de7796..f9e450b559208 100755 --- a/scripts/release/publish.js +++ b/scripts/release/publish.js @@ -23,14 +23,27 @@ const run = async () => { try { const params = parseParams(); - const version = readJsonSync( - './build/node_modules/react/package.json' - ).version; + const version = + params.publishVersion ?? + readJsonSync('./build/node_modules/react/package.json').version; const isExperimental = version.includes('experimental'); params.cwd = join(__dirname, '..', '..'); params.packages = await getPublicPackages(isExperimental); + if (params.onlyPackages.length > 0 && params.skipPackages.length > 0) { + console.error( + '--onlyPackages and --skipPackages cannot be used together' + ); + process.exit(1); + } + + if (params.onlyPackages.length > 0) { + params.packages = params.packages.filter(packageName => { + return params.onlyPackages.includes(packageName); + }); + } + // Pre-filter any skipped packages to simplify the following commands. // As part of doing this we can also validate that none of the skipped packages were misspelled. params.skipPackages.forEach(packageName => {