diff --git a/compiler/apps/playground/package.json b/compiler/apps/playground/package.json index c3dd825f1a16f..9b43f18f0e8c4 100644 --- a/compiler/apps/playground/package.json +++ b/compiler/apps/playground/package.json @@ -3,10 +3,11 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "cd ../.. && concurrently --kill-others -n compiler,runtime,playground \"yarn workspace babel-plugin-react-compiler run build --watch\" \"yarn workspace react-compiler-runtime run build --watch\" \"wait-on packages/babel-plugin-react-compiler/dist/index.js && cd apps/playground && NODE_ENV=development next dev\"", + "dev": "cd ../.. && concurrently --kill-others -n compiler,runtime,playground \"yarn workspace babel-plugin-react-compiler run watch\" \"yarn workspace react-compiler-runtime run watch\" \"wait-on packages/babel-plugin-react-compiler/dist/index.js && cd apps/playground && NODE_ENV=development next dev\"", "build:compiler": "cd ../.. && concurrently -n compiler,runtime \"yarn workspace babel-plugin-react-compiler run build\" \"yarn workspace react-compiler-runtime run build\"", "build": "yarn build:compiler && next build", "postbuild": "node ./scripts/downloadFonts.js", + "preinstall": "cd ../.. && yarn install --frozen-lockfile", "postinstall": "./scripts/link-compiler.sh", "vercel-build": "yarn build", "start": "next start", diff --git a/compiler/package.json b/compiler/package.json index b25031b9967d8..05e3b6c5abe87 100644 --- a/compiler/package.json +++ b/compiler/package.json @@ -15,7 +15,7 @@ "start": "yarn workspace playground run start", "next": "yarn workspace playground run dev", "build": "yarn workspaces run build", - "dev": "echo 'DEPRECATED: use `cd apps/playground && yarn dev` instead!' && sleep 5 && cd apps/playground && yarn dev", + "dev": "cd apps/playground && yarn dev", "test": "yarn workspaces run test", "snap": "yarn workspace babel-plugin-react-compiler run snap", "snap:build": "yarn workspace snap run build", @@ -26,22 +26,15 @@ "react-is": "0.0.0-experimental-4beb1fd8-20241118" }, "devDependencies": { - "@rollup/plugin-commonjs": "^28.0.2", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^16.0.0", - "@rollup/plugin-terser": "^0.4.4", - "@rollup/plugin-typescript": "^12.1.2", "@tsconfig/strictest": "^2.0.5", "concurrently": "^7.4.0", + "esbuild": "^0.24.2", "folder-hash": "^4.0.4", "object-assign": "^4.1.1", "ora": "5.4.1", "prettier": "^3.3.3", - "prettier-plugin-hermes-parser": "^0.25.1", + "prettier-plugin-hermes-parser": "^0.26.0", "prompt-promise": "^1.0.3", - "rollup": "^4.22.4", - "rollup-plugin-banner2": "^1.2.3", - "rollup-plugin-prettier": "^4.1.1", "typescript": "^5.4.3", "wait-on": "^7.2.0", "yargs": "^17.7.2" diff --git a/compiler/packages/babel-plugin-react-compiler/package.json b/compiler/packages/babel-plugin-react-compiler/package.json index 158b800dba900..eb6c3cc628eb2 100644 --- a/compiler/packages/babel-plugin-react-compiler/package.json +++ b/compiler/packages/babel-plugin-react-compiler/package.json @@ -9,14 +9,15 @@ "!*.tsbuildinfo" ], "scripts": { - "build": "rimraf dist && rollup --config --bundleConfigAsCjs", + "build": "rimraf dist && scripts/build.js", "test": "./scripts/link-react-compiler-runtime.sh && yarn snap:ci", "jest": "yarn build && ts-node node_modules/.bin/jest", "snap": "node ../snap/dist/main.js", "snap:build": "yarn workspace snap run build", "snap:ci": "yarn snap:build && yarn snap", "ts:analyze-trace": "scripts/ts-analyze-trace.sh", - "lint": "yarn eslint src" + "lint": "yarn eslint src", + "watch": "scripts/build.js --watch" }, "dependencies": { "@babel/types": "^7.19.0" diff --git a/compiler/packages/babel-plugin-react-compiler/rollup.config.js b/compiler/packages/babel-plugin-react-compiler/rollup.config.js deleted file mode 100644 index b95cc89b39b13..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/rollup.config.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * 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 typescript from '@rollup/plugin-typescript'; -import {nodeResolve} from '@rollup/plugin-node-resolve'; -import commonjs from '@rollup/plugin-commonjs'; -import json from '@rollup/plugin-json'; -import path from 'path'; -import process from 'process'; -import terser from '@rollup/plugin-terser'; -import prettier from 'rollup-plugin-prettier'; -import banner2 from 'rollup-plugin-banner2'; - -const NO_INLINE = new Set(['@babel/types']); - -const DEV_ROLLUP_CONFIG = { - input: 'src/index.ts', - output: { - file: 'dist/index.js', - format: 'cjs', - sourcemap: false, - exports: 'named', - inlineDynamicImports: true, - }, - plugins: [ - typescript({ - tsconfig: './tsconfig.json', - outputToFilesystem: true, - compilerOptions: { - noEmit: true, - }, - }), - json(), - nodeResolve({ - preferBuiltins: true, - resolveOnly: module => NO_INLINE.has(module) === false, - rootDir: path.join(process.cwd(), '..'), - }), - commonjs(), - terser({ - format: { - comments: false, - }, - compress: false, - mangle: false, - }), - prettier(), - banner2( - () => `/** - * 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 - */ - -"use no memo"; -` - ), - ], -}; - -export default DEV_ROLLUP_CONFIG; diff --git a/compiler/packages/babel-plugin-react-compiler/scripts/build.js b/compiler/packages/babel-plugin-react-compiler/scripts/build.js new file mode 100755 index 0000000000000..5c451f11f99f9 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/scripts/build.js @@ -0,0 +1,61 @@ +#!/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. + */ + +const esbuild = require('esbuild'); +const yargs = require('yargs'); +const path = require('path'); + +const argv = yargs(process.argv.slice(2)) + .options('w', { + alias: 'watch', + default: false, + type: 'boolean', + }) + .parse(); + +const config = { + entryPoints: [path.join(__dirname, '../src/index.ts')], + outfile: path.join(__dirname, '../dist/index.js'), + bundle: true, + external: ['@babel/types'], + 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 + */ + +"use no memo";`, + }, +}; + +async function main() { + if (argv.w) { + const ctx = await esbuild.context(config); + await ctx.watch(); + console.log('watching for changes...'); + } else { + await esbuild.build({ + sourcemap: true, + minify: false, + ...config, + }); + } +} + +main(); diff --git a/compiler/packages/eslint-plugin-react-compiler/package.json b/compiler/packages/eslint-plugin-react-compiler/package.json index eec2c9424846a..d325b3f3d1c67 100644 --- a/compiler/packages/eslint-plugin-react-compiler/package.json +++ b/compiler/packages/eslint-plugin-react-compiler/package.json @@ -4,8 +4,9 @@ "description": "ESLint plugin to display errors found by the React compiler.", "main": "dist/index.js", "scripts": { - "build": "rimraf dist && rollup --config --bundleConfigAsCjs", - "test": "tsc && jest" + "build": "rimraf dist && scripts/build.js", + "test": "tsc && jest", + "watch": "scripts/build.js --watch" }, "files": [ "dist" diff --git a/compiler/packages/eslint-plugin-react-compiler/rollup.config.js b/compiler/packages/eslint-plugin-react-compiler/rollup.config.js deleted file mode 100644 index 743e4cc844102..0000000000000 --- a/compiler/packages/eslint-plugin-react-compiler/rollup.config.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * 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 typescript from '@rollup/plugin-typescript'; -import {nodeResolve} from '@rollup/plugin-node-resolve'; -import commonjs from '@rollup/plugin-commonjs'; -import json from '@rollup/plugin-json'; -import path from 'path'; -import process from 'process'; -import terser from '@rollup/plugin-terser'; -import prettier from 'rollup-plugin-prettier'; -import banner2 from 'rollup-plugin-banner2'; - -const NO_INLINE = new Set([ - '@babel/core', - '@babel/plugin-proposal-private-methods', - 'hermes-parser', - 'zod', - 'zod-validation-error', -]); - -const DEV_ROLLUP_CONFIG = { - input: 'src/index.ts', - output: { - file: 'dist/index.js', - format: 'cjs', - sourcemap: false, - inlineDynamicImports: true, - }, - treeshake: { - moduleSideEffects: false, - }, - plugins: [ - typescript({ - compilerOptions: { - noEmit: true, - }, - }), - json(), - nodeResolve({ - preferBuiltins: true, - resolveOnly: module => NO_INLINE.has(module) === false, - rootDir: path.join(process.cwd(), '..'), - }), - commonjs(), - terser({ - format: { - comments: false, - }, - compress: false, - mangle: false, - }), - prettier(), - banner2( - () => `/** - * 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 - */ - -"use no memo"; -` - ), - ], -}; - -export default DEV_ROLLUP_CONFIG; diff --git a/compiler/packages/eslint-plugin-react-compiler/scripts/build.js b/compiler/packages/eslint-plugin-react-compiler/scripts/build.js new file mode 100755 index 0000000000000..d201f38b89570 --- /dev/null +++ b/compiler/packages/eslint-plugin-react-compiler/scripts/build.js @@ -0,0 +1,67 @@ +#!/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. + */ + +const esbuild = require('esbuild'); +const yargs = require('yargs'); +const path = require('path'); + +const argv = yargs(process.argv.slice(2)) + .options('w', { + alias: 'watch', + default: false, + type: 'boolean', + }) + .parse(); + +const config = { + entryPoints: [path.join(__dirname, '../src/index.ts')], + outfile: path.join(__dirname, '../dist/index.js'), + bundle: true, + external: [ + '@babel/core', + '@babel/plugin-proposal-private-methods', + 'hermes-parser', + 'zod', + 'zod-validation-error', + ], + 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 + */ + +"use no memo";`, + }, +}; + +async function main() { + if (argv.w) { + const ctx = await esbuild.context(config); + await ctx.watch(); + console.log('watching for changes...'); + } else { + await esbuild.build({ + sourcemap: true, + minify: false, + ...config, + }); + } +} + +main(); diff --git a/compiler/packages/make-read-only-util/package.json b/compiler/packages/make-read-only-util/package.json index 212d934669d5d..59293c1771c0b 100644 --- a/compiler/packages/make-read-only-util/package.json +++ b/compiler/packages/make-read-only-util/package.json @@ -1,12 +1,14 @@ { "name": "make-read-only-util", "version": "0.0.1", + "license": "MIT", "files": [ "src" ], "scripts": { - "build": "tsc", - "test": "jest src" + "build": "rimraf dist && scripts/build.js", + "test": "jest src", + "watch": "scripts/build.js --watch" }, "dependencies": { "invariant": "^2.2.4", diff --git a/compiler/packages/make-read-only-util/scripts/build.js b/compiler/packages/make-read-only-util/scripts/build.js new file mode 100755 index 0000000000000..91301c3b6a0f2 --- /dev/null +++ b/compiler/packages/make-read-only-util/scripts/build.js @@ -0,0 +1,61 @@ +#!/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. + */ + +const esbuild = require('esbuild'); +const yargs = require('yargs'); +const path = require('path'); + +const argv = yargs(process.argv.slice(2)) + .options('w', { + alias: 'watch', + default: false, + type: 'boolean', + }) + .parse(); + +const config = { + entryPoints: [path.join(__dirname, '../src/makeReadOnly.ts')], + outfile: path.join(__dirname, '../dist/index.js'), + bundle: true, + format: 'esm', + platform: 'browser', + target: 'es6', + 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 + */ + +"use no memo";`, + }, +}; + +async function main() { + if (argv.w) { + const ctx = await esbuild.context(config); + await ctx.watch(); + console.log('watching for changes...'); + } else { + await esbuild.build({ + sourcemap: true, + minify: false, + ...config, + }); + } +} + +main(); diff --git a/compiler/packages/react-compiler-healthcheck/package.json b/compiler/packages/react-compiler-healthcheck/package.json index 673e18d8ebb34..44a52151bbbb4 100644 --- a/compiler/packages/react-compiler-healthcheck/package.json +++ b/compiler/packages/react-compiler-healthcheck/package.json @@ -6,8 +6,9 @@ "react-compiler-healthcheck": "dist/index.js" }, "scripts": { - "build": "rimraf dist && rollup --config --bundleConfigAsCjs", - "test": "echo 'no tests'" + "build": "rimraf dist && scripts/build.js", + "test": "echo 'no tests'", + "watch": "scripts/build.js --watch" }, "dependencies": { "@babel/core": "^7.24.4", diff --git a/compiler/packages/react-compiler-healthcheck/rollup.config.js b/compiler/packages/react-compiler-healthcheck/rollup.config.js deleted file mode 100644 index 0c2492d14069d..0000000000000 --- a/compiler/packages/react-compiler-healthcheck/rollup.config.js +++ /dev/null @@ -1,82 +0,0 @@ -/** - * 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 typescript from '@rollup/plugin-typescript'; -import {nodeResolve} from '@rollup/plugin-node-resolve'; -import commonjs from '@rollup/plugin-commonjs'; -import json from '@rollup/plugin-json'; -import path from 'path'; -import process from 'process'; -import terser from '@rollup/plugin-terser'; -import prettier from 'rollup-plugin-prettier'; -import banner2 from 'rollup-plugin-banner2'; - -const NO_INLINE = new Set([ - '@babel/core', - '@babel/parser', - 'chalk', - 'fast-glob', - 'ora', - 'yargs', - 'zod', - 'zod-validation-error', -]); - -const DEV_ROLLUP_CONFIG = { - input: 'src/index.ts', - output: { - file: 'dist/index.js', - format: 'cjs', - sourcemap: false, - exports: 'named', - inlineDynamicImports: true, - }, - plugins: [ - typescript({ - tsconfig: './tsconfig.json', - compilerOptions: { - noEmit: true, - }, - }), - json(), - nodeResolve({ - preferBuiltins: true, - resolveOnly: module => NO_INLINE.has(module) === false, - rootDir: path.join(process.cwd(), '..'), - }), - commonjs(), - terser({ - format: { - comments: false, - }, - compress: false, - mangle: false, - }), - prettier(), - banner2( - () => `#!/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. - * - * @lightSyntaxTransform - * @noflow - * @nolint - * @preventMunge - * @preserve-invariant-messages - */ - -"use no memo"; -` - ), - ], -}; - -export default DEV_ROLLUP_CONFIG; diff --git a/compiler/packages/react-compiler-healthcheck/scripts/build.js b/compiler/packages/react-compiler-healthcheck/scripts/build.js new file mode 100755 index 0000000000000..b8e0f88d6c8a5 --- /dev/null +++ b/compiler/packages/react-compiler-healthcheck/scripts/build.js @@ -0,0 +1,70 @@ +#!/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. + */ + +const esbuild = require('esbuild'); +const yargs = require('yargs'); +const path = require('path'); + +const argv = yargs(process.argv.slice(2)) + .options('w', { + alias: 'watch', + default: false, + type: 'boolean', + }) + .parse(); + +const config = { + entryPoints: [path.join(__dirname, '../src/index.ts')], + outfile: path.join(__dirname, '../dist/index.js'), + bundle: true, + external: [ + '@babel/core', + '@babel/parser', + 'chalk', + 'fast-glob', + 'ora', + 'yargs', + 'zod', + 'zod-validation-error', + ], + 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 + */ + +"use no memo";`, + }, +}; + +async function main() { + if (argv.w) { + const ctx = await esbuild.context(config); + await ctx.watch(); + console.log('watching for changes...'); + } else { + await esbuild.build({ + sourcemap: true, + minify: false, + ...config, + }); + } +} + +main(); diff --git a/compiler/packages/react-compiler-runtime/package.json b/compiler/packages/react-compiler-runtime/package.json index d72f168c56aad..097ab56c7a72f 100644 --- a/compiler/packages/react-compiler-runtime/package.json +++ b/compiler/packages/react-compiler-runtime/package.json @@ -12,8 +12,9 @@ "react": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^0.0.0-experimental" }, "scripts": { - "build": "rimraf dist && rollup --config --bundleConfigAsCjs", - "test": "echo 'no tests'" + "build": "rimraf dist && scripts/build.js", + "test": "echo 'no tests'", + "watch": "scripts/build.js --watch" }, "repository": { "type": "git", diff --git a/compiler/packages/react-compiler-runtime/rollup.config.js b/compiler/packages/react-compiler-runtime/rollup.config.js deleted file mode 100644 index 2399f2160c223..0000000000000 --- a/compiler/packages/react-compiler-runtime/rollup.config.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * 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 typescript from '@rollup/plugin-typescript'; -import {nodeResolve} from '@rollup/plugin-node-resolve'; -import commonjs from '@rollup/plugin-commonjs'; -import json from '@rollup/plugin-json'; -import path from 'path'; -import process from 'process'; -import banner2 from 'rollup-plugin-banner2'; - -const NO_INLINE = new Set(['react']); - -const PROD_ROLLUP_CONFIG = { - input: 'src/index.ts', - output: { - file: 'dist/index.js', - format: 'cjs', - sourcemap: true, - inlineDynamicImports: true, - }, - plugins: [ - typescript({ - tsconfig: './tsconfig.json', - compilerOptions: { - noEmit: true, - }, - }), - json(), - nodeResolve({ - preferBuiltins: true, - resolveOnly: module => NO_INLINE.has(module) === false, - rootDir: path.join(process.cwd(), '..'), - }), - commonjs(), - banner2( - () => `/** - * 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 - */ - -"use no memo";` // DO NOT REMOVE - ), - ], -}; - -export default PROD_ROLLUP_CONFIG; diff --git a/compiler/packages/react-compiler-runtime/scripts/build.js b/compiler/packages/react-compiler-runtime/scripts/build.js new file mode 100755 index 0000000000000..c64a0fd16ed34 --- /dev/null +++ b/compiler/packages/react-compiler-runtime/scripts/build.js @@ -0,0 +1,67 @@ +#!/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. + */ + +const esbuild = require('esbuild'); +const yargs = require('yargs'); +const path = require('path'); + +const argv = yargs(process.argv.slice(2)) + .options('p', { + alias: 'platform', + default: 'browser', + choices: ['browser', 'node'], + }) + .options('w', { + alias: 'watch', + default: false, + type: 'boolean', + }) + .parse(); + +const config = { + entryPoints: [path.join(__dirname, '../src/index.ts')], + outfile: path.join(__dirname, '../dist/index.js'), + bundle: true, + external: ['react'], + format: argv.p === 'browser' ? 'esm' : 'cjs', + platform: argv.p, + target: 'es6', + 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 + */ + +"use no memo";`, + }, +}; + +async function main() { + if (argv.w) { + const ctx = await esbuild.context(config); + await ctx.watch(); + console.log('watching for changes...'); + } else { + await esbuild.build({ + sourcemap: true, + minify: false, + ...config, + }); + } +} + +main(); diff --git a/compiler/packages/react-compiler-runtime/src/index.ts b/compiler/packages/react-compiler-runtime/src/index.ts index 57f61f3e8c017..bdaface961ed5 100644 --- a/compiler/packages/react-compiler-runtime/src/index.ts +++ b/compiler/packages/react-compiler-runtime/src/index.ts @@ -5,8 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -'use no memo'; - import * as React from 'react'; const {useRef, useEffect, isValidElement} = React; diff --git a/compiler/packages/snap/package.json b/compiler/packages/snap/package.json index e4d7b051d05a5..0fc00fab58020 100644 --- a/compiler/packages/snap/package.json +++ b/compiler/packages/snap/package.json @@ -10,7 +10,7 @@ ], "scripts": { "postinstall": "./scripts/link-react-compiler-runtime.sh && perl -p -i -e 's/react\\.element/react.transitional.element/' ../../node_modules/fbt/lib/FbtReactUtil.js && perl -p -i -e 's/didWarnAboutUsingAct = false;/didWarnAboutUsingAct = true;/' ../../node_modules/react-dom/cjs/react-dom-test-utils.development.js", - "build": "rimraf dist && concurrently -n snap,runtime \"tsc --build\" \"yarn --silent workspace react-compiler-runtime build --silent\"", + "build": "rimraf dist && concurrently -n snap,runtime \"tsc --build\" \"yarn --silent workspace react-compiler-runtime build -p node\"", "test": "echo 'no tests'", "prettier": "prettier --write 'src/**/*.ts'" }, diff --git a/compiler/scripts/release/shared/build-packages.js b/compiler/scripts/release/shared/build-packages.js index 9041416b778a8..4152f61271104 100644 --- a/compiler/scripts/release/shared/build-packages.js +++ b/compiler/scripts/release/shared/build-packages.js @@ -4,7 +4,7 @@ const {execHelper} = require('./utils'); async function buildPackages(pkgNames) { const spinner = ora(`Building packages`).info(); for (const pkgName of pkgNames) { - const command = `yarn workspace ${pkgName} run build`; + const command = `NODE_ENV=production yarn workspace ${pkgName} run build`; spinner.start(`Running: ${command}\n`); try { await execHelper(command); diff --git a/compiler/yarn.lock b/compiler/yarn.lock index 21f771c93fd68..2723d1722013f 100644 --- a/compiler/yarn.lock +++ b/compiler/yarn.lock @@ -44,7 +44,7 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.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== @@ -59,9 +59,9 @@ integrity sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ== "@babel/compat-data@^7.25.9": - version "7.26.2" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.2.tgz#278b6b13664557de95b8f35b90d96785850bb56e" - integrity sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg== + 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.0.0", "@babel/core@^7.2.0": version "7.2.0" @@ -115,13 +115,13 @@ source-map "^0.5.0" trim-right "^1.0.1" -"@babel/generator@^7.25.9", "@babel/generator@^7.26.0", "@babel/generator@^7.7.2", "@babel/generator@^7.7.4": - version "7.26.2" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.2.tgz#87b75813bec87916210e5e01939a4c823d6bb74f" - integrity sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw== +"@babel/generator@^7.26.0", "@babel/generator@^7.26.3", "@babel/generator@^7.7.2", "@babel/generator@^7.7.4": + 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.2" - "@babel/types" "^7.26.0" + "@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" @@ -675,12 +675,12 @@ dependencies: "@babel/types" "^7.25.6" -"@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.2": - version "7.26.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.2.tgz#fd7b6f487cfea09889557ef5d4eeb9ff9a5abd11" - integrity sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ== +"@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.0" + "@babel/types" "^7.26.3" "@babel/parser@^7.7.4": version "7.21.4" @@ -1606,15 +1606,15 @@ lodash "^4.17.13" "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.5", "@babel/traverse@^7.21.2", "@babel/traverse@^7.22.1", "@babel/traverse@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84" - integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw== + 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.25.9" - "@babel/generator" "^7.25.9" - "@babel/parser" "^7.25.9" + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.3" + "@babel/parser" "^7.26.3" "@babel/template" "^7.25.9" - "@babel/types" "^7.25.9" + "@babel/types" "^7.26.3" debug "^4.3.1" globals "^11.1.0" @@ -1680,10 +1680,10 @@ "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" -"@babel/types@^7.25.9", "@babel/types@^7.26.0": - version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.0.tgz#deabd08d6b753bc8e0f198f8709fb575e31774ff" - integrity sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA== +"@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" @@ -1700,6 +1700,131 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@esbuild/aix-ppc64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz#38848d3e25afe842a7943643cbcd387cc6e13461" + integrity sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA== + +"@esbuild/android-arm64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz#f592957ae8b5643129fa889c79e69cd8669bb894" + integrity sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg== + +"@esbuild/android-arm@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.24.2.tgz#72d8a2063aa630308af486a7e5cbcd1e134335b3" + integrity sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q== + +"@esbuild/android-x64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.24.2.tgz#9a7713504d5f04792f33be9c197a882b2d88febb" + integrity sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw== + +"@esbuild/darwin-arm64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz#02ae04ad8ebffd6e2ea096181b3366816b2b5936" + integrity sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA== + +"@esbuild/darwin-x64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz#9ec312bc29c60e1b6cecadc82bd504d8adaa19e9" + integrity sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA== + +"@esbuild/freebsd-arm64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz#5e82f44cb4906d6aebf24497d6a068cfc152fa00" + integrity sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg== + +"@esbuild/freebsd-x64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz#3fb1ce92f276168b75074b4e51aa0d8141ecce7f" + integrity sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q== + +"@esbuild/linux-arm64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz#856b632d79eb80aec0864381efd29de8fd0b1f43" + integrity sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg== + +"@esbuild/linux-arm@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz#c846b4694dc5a75d1444f52257ccc5659021b736" + integrity sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA== + +"@esbuild/linux-ia32@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz#f8a16615a78826ccbb6566fab9a9606cfd4a37d5" + integrity sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw== + +"@esbuild/linux-loong64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz#1c451538c765bf14913512c76ed8a351e18b09fc" + integrity sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ== + +"@esbuild/linux-mips64el@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz#0846edeefbc3d8d50645c51869cc64401d9239cb" + integrity sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw== + +"@esbuild/linux-ppc64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz#8e3fc54505671d193337a36dfd4c1a23b8a41412" + integrity sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw== + +"@esbuild/linux-riscv64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz#6a1e92096d5e68f7bb10a0d64bb5b6d1daf9a694" + integrity sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q== + +"@esbuild/linux-s390x@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz#ab18e56e66f7a3c49cb97d337cd0a6fea28a8577" + integrity sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw== + +"@esbuild/linux-x64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz#8140c9b40da634d380b0b29c837a0b4267aff38f" + integrity sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q== + +"@esbuild/netbsd-arm64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz#65f19161432bafb3981f5f20a7ff45abb2e708e6" + integrity sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw== + +"@esbuild/netbsd-x64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz#7a3a97d77abfd11765a72f1c6f9b18f5396bcc40" + integrity sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw== + +"@esbuild/openbsd-arm64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz#58b00238dd8f123bfff68d3acc53a6ee369af89f" + integrity sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A== + +"@esbuild/openbsd-x64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz#0ac843fda0feb85a93e288842936c21a00a8a205" + integrity sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA== + +"@esbuild/sunos-x64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz#8b7aa895e07828d36c422a4404cc2ecf27fb15c6" + integrity sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig== + +"@esbuild/win32-arm64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz#c023afb647cabf0c3ed13f0eddfc4f1d61c66a85" + integrity sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ== + +"@esbuild/win32-ia32@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz#96c356132d2dda990098c8b8b951209c3cd743c2" + integrity sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA== + +"@esbuild/win32-x64@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz#34aa0b52d0fbb1a654b596acfa595f0c7b77a77b" + integrity sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -2426,20 +2551,12 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/source-map@^0.3.3": - version "0.3.6" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" - integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - "@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": +"@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -2512,152 +2629,6 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@rollup/plugin-commonjs@^28.0.2": - version "28.0.2" - resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.2.tgz#193d7a86470f112b56927c1d821ee45951a819ea" - integrity sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw== - dependencies: - "@rollup/pluginutils" "^5.0.1" - commondir "^1.0.1" - estree-walker "^2.0.2" - fdir "^6.2.0" - is-reference "1.2.1" - magic-string "^0.30.3" - picomatch "^4.0.2" - -"@rollup/plugin-json@^6.1.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-6.1.0.tgz#fbe784e29682e9bb6dee28ea75a1a83702e7b805" - integrity sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA== - dependencies: - "@rollup/pluginutils" "^5.1.0" - -"@rollup/plugin-node-resolve@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.0.tgz#b1a0594661f40d7b061d82136e847354ff85f211" - integrity sha512-0FPvAeVUT/zdWoO0jnb/V5BlBsUSNfkIOtFHzMO4H9MOklrmQFY6FduVHKucNb/aTFxvnGhj4MNj/T1oNdDfNg== - dependencies: - "@rollup/pluginutils" "^5.0.1" - "@types/resolve" "1.20.2" - deepmerge "^4.2.2" - is-module "^1.0.0" - resolve "^1.22.1" - -"@rollup/plugin-terser@^0.4.4": - version "0.4.4" - resolved "https://registry.yarnpkg.com/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz#15dffdb3f73f121aa4fbb37e7ca6be9aeea91962" - integrity sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A== - dependencies: - serialize-javascript "^6.0.1" - smob "^1.0.0" - terser "^5.17.4" - -"@rollup/plugin-typescript@^12.1.2": - version "12.1.2" - resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-12.1.2.tgz#ebaeec2e7376faa889030ccd7cb485a649e63118" - integrity sha512-cdtSp154H5sv637uMr1a8OTWB0L1SWDSm1rDGiyfcGcvQ6cuTs4MDk2BVEBGysUWago4OJN4EQZqOTl/QY3Jgg== - dependencies: - "@rollup/pluginutils" "^5.1.0" - resolve "^1.22.1" - -"@rollup/pluginutils@^5.0.1": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.4.tgz#74f808f9053d33bafec0cc98e7b835c9667d32ba" - integrity sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g== - dependencies: - "@types/estree" "^1.0.0" - estree-walker "^2.0.2" - picomatch "^2.3.1" - -"@rollup/pluginutils@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0" - integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== - dependencies: - "@types/estree" "^1.0.0" - estree-walker "^2.0.2" - picomatch "^2.3.1" - -"@rollup/rollup-android-arm-eabi@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz#8b613b9725e8f9479d142970b106b6ae878610d5" - integrity sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w== - -"@rollup/rollup-android-arm64@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz#654ca1049189132ff602bfcf8df14c18da1f15fb" - integrity sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA== - -"@rollup/rollup-darwin-arm64@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz#6d241d099d1518ef0c2205d96b3fa52e0fe1954b" - integrity sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q== - -"@rollup/rollup-darwin-x64@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz#42bd19d292a57ee11734c980c4650de26b457791" - integrity sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw== - -"@rollup/rollup-linux-arm-gnueabihf@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz#f23555ee3d8fe941c5c5fd458cd22b65eb1c2232" - integrity sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ== - -"@rollup/rollup-linux-arm-musleabihf@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz#f3bbd1ae2420f5539d40ac1fde2b38da67779baa" - integrity sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg== - -"@rollup/rollup-linux-arm64-gnu@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz#7abe900120113e08a1f90afb84c7c28774054d15" - integrity sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw== - -"@rollup/rollup-linux-arm64-musl@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz#9e655285c8175cd44f57d6a1e8e5dedfbba1d820" - integrity sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA== - -"@rollup/rollup-linux-powerpc64le-gnu@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz#9a79ae6c9e9d8fe83d49e2712ecf4302db5bef5e" - integrity sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg== - -"@rollup/rollup-linux-riscv64-gnu@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz#67ac70eca4ace8e2942fabca95164e8874ab8128" - integrity sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA== - -"@rollup/rollup-linux-s390x-gnu@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz#9f883a7440f51a22ed7f99e1d070bd84ea5005fc" - integrity sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q== - -"@rollup/rollup-linux-x64-gnu@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz#70116ae6c577fe367f58559e2cffb5641a1dd9d0" - integrity sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg== - -"@rollup/rollup-linux-x64-musl@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz#f473f88219feb07b0b98b53a7923be716d1d182f" - integrity sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g== - -"@rollup/rollup-win32-arm64-msvc@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz#4349482d17f5d1c58604d1c8900540d676f420e0" - integrity sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw== - -"@rollup/rollup-win32-ia32-msvc@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz#a6fc39a15db618040ec3c2a24c1e26cb5f4d7422" - integrity sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g== - -"@rollup/rollup-win32-x64-msvc@4.22.4": - version "4.22.4" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz#3dd5d53e900df2a40841882c02e56f866c04d202" - integrity sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q== - "@sideway/address@^4.1.5": version "4.1.5" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" @@ -2822,7 +2793,7 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0": +"@types/estree@*": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== @@ -2926,13 +2897,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.5.tgz#26d295f3570323b2837d322180dfbf1ba156fefb" integrity sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ== -"@types/prettier@^1.0.0 || ^2.0.0 || ^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-3.0.0.tgz#e9bc8160230d3a461dab5c5b41cceef1ef723057" - integrity sha512-mFMBfMOz8QxhYVbuINtswBp9VL2b4Y0QqYHwqLz3YbgtfAcat2Dl6Y1o4e22S/OVE6Ebl9m7wWiMT2lSbAs1wA== - dependencies: - prettier "*" - "@types/prettier@^2.1.5": version "2.7.0" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.0.tgz#ea03e9f0376a4446f44797ca19d9c46c36e352dc" @@ -2959,11 +2923,6 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/resolve@1.20.2": - version "1.20.2" - resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" - integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== - "@types/scheduler@*": version "0.16.2" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" @@ -3213,11 +3172,6 @@ acorn@^8.4.1, acorn@^8.7.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== -acorn@^8.8.2: - version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== - acorn@^8.9.0: version "8.11.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" @@ -3585,13 +3539,13 @@ browserslist@^4.21.3, browserslist@^4.21.5: update-browserslist-db "^1.0.11" browserslist@^4.24.0: - version "4.24.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580" - integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg== + 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.30001669" - electron-to-chromium "^1.5.41" - node-releases "^2.0.18" + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" update-browserslist-db "^1.1.1" bs-logger@0.x: @@ -3649,10 +3603,10 @@ caniuse-lite@^1.0.30001489: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz" integrity sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ== -caniuse-lite@^1.0.30001669: - version "1.0.30001680" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz#5380ede637a33b9f9f1fc6045ea99bd142f3da5e" - integrity sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA== +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== chalk@4, chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" @@ -3787,11 +3741,6 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -3981,11 +3930,6 @@ diff-sequences@^29.4.3: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== -diff@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" - integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== - diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -4041,10 +3985,10 @@ electron-to-chromium@^1.4.411: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.418.tgz#9092aca12db25acf02a2ddf9de59f0e4363c9928" integrity sha512-1KnpDTS9onwAfMzW50LcpNtyOkMyjd/OLoD2Kx/DDITZqgNYixY71XNszPHNxyQQ/Brh+FDcUnf4BaM041sdWg== -electron-to-chromium@^1.5.41: - version "1.5.63" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.63.tgz#69444d592fbbe628d129866c2355691ea93eda3e" - integrity sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA== +electron-to-chromium@^1.5.73: + version "1.5.76" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz#db20295c5061b68f07c8ea4dfcbd701485d94a3d" + integrity sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ== emittery@^0.10.2: version "0.10.2" @@ -4083,6 +4027,37 @@ es5-ext@0.8.x: resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.8.2.tgz#aba8d9e1943a895ac96837a62a39b3f55ecd94ab" integrity sha512-H19ompyhnKiBdjHR1DPHvf5RHgHPmJaY9JNzFGbMbPgdsUkvnUCN1Ke8J4Y0IMyTwFM2M9l4h2GoHwzwpSmXbA== +esbuild@^0.24.2: + version "0.24.2" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.24.2.tgz#b5b55bee7de017bff5fb8a4e3e44f2ebe2c3567d" + integrity sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA== + optionalDependencies: + "@esbuild/aix-ppc64" "0.24.2" + "@esbuild/android-arm" "0.24.2" + "@esbuild/android-arm64" "0.24.2" + "@esbuild/android-x64" "0.24.2" + "@esbuild/darwin-arm64" "0.24.2" + "@esbuild/darwin-x64" "0.24.2" + "@esbuild/freebsd-arm64" "0.24.2" + "@esbuild/freebsd-x64" "0.24.2" + "@esbuild/linux-arm" "0.24.2" + "@esbuild/linux-arm64" "0.24.2" + "@esbuild/linux-ia32" "0.24.2" + "@esbuild/linux-loong64" "0.24.2" + "@esbuild/linux-mips64el" "0.24.2" + "@esbuild/linux-ppc64" "0.24.2" + "@esbuild/linux-riscv64" "0.24.2" + "@esbuild/linux-s390x" "0.24.2" + "@esbuild/linux-x64" "0.24.2" + "@esbuild/netbsd-arm64" "0.24.2" + "@esbuild/netbsd-x64" "0.24.2" + "@esbuild/openbsd-arm64" "0.24.2" + "@esbuild/openbsd-x64" "0.24.2" + "@esbuild/sunos-x64" "0.24.2" + "@esbuild/win32-arm64" "0.24.2" + "@esbuild/win32-ia32" "0.24.2" + "@esbuild/win32-x64" "0.24.2" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -4264,11 +4239,6 @@ estraverse@^5.1.0, estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-walker@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" - integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== - esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -4403,11 +4373,6 @@ fbt@^1.0.2: dependencies: invariant "^2.2.4" -fdir@^6.2.0: - version "6.4.2" - resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.2.tgz#ddaa7ce1831b161bc3657bb99cb36e1622702689" - integrity sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ== - file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -4516,7 +4481,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.2: +fsevents@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -4679,6 +4644,11 @@ hermes-estree@0.25.1: resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.25.1.tgz#6aeec17d1983b4eabf69721f3aa3eb705b17f480" integrity sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw== +hermes-estree@0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.26.0.tgz#70da6d2e7131ec2693dac8e596e76957c4ce76ef" + integrity sha512-If1T7lhfXnGlVLbnsmwerNB5cyJm2oIE8TN1UKEq6/OUX1nOGUhjXMpqAwZ1wkkn9Brda0VRyJEWOGT2GgVcAQ== + hermes-parser@0.25.1, hermes-parser@^0.25.1: version "0.25.1" resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.25.1.tgz#5be0e487b2090886c62bd8a11724cd766d5f54d1" @@ -4686,6 +4656,13 @@ hermes-parser@0.25.1, hermes-parser@^0.25.1: dependencies: hermes-estree "0.25.1" +hermes-parser@0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.26.0.tgz#4968f8ad923a8064a65d0c1e037d754fd3a45c66" + integrity sha512-fWT40jJ/BtlzuyiiQS7lzNIlB5h6flVZoN8Jn8v5l987HL5dK9s+/4+py0FaBmeIEROC2zxt5qMLwXFTPLQ7BA== + dependencies: + hermes-estree "0.26.0" + html-encoding-sniffer@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" @@ -4834,11 +4811,6 @@ 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-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" - integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -4861,13 +4833,6 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-reference@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" - integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== - dependencies: - "@types/estree" "*" - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" @@ -6127,9 +6092,9 @@ jsesc@^2.5.1: integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== jsesc@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" - integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== jsesc@~0.5.0: version "0.5.0" @@ -6240,21 +6205,6 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== -lodash.hasin@4.5.2: - version "4.5.2" - resolved "https://registry.yarnpkg.com/lodash.hasin/-/lodash.hasin-4.5.2.tgz#f91e352378d21ef7090b9e7687c2ca35c5b4d52a" - integrity sha512-AFAitwTSq1Ka/1J9uBaVxpLBP5OI3INQvkl4wKcgIYxoA0S3aqO1QWXHR9aCcOrWtPFqP7GzlFncZfe0Jz0kNw== - -lodash.isempty@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" - integrity sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg== - -lodash.isnil@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/lodash.isnil/-/lodash.isnil-4.0.0.tgz#49e28cd559013458c814c5479d3c663a21bfaa6c" - integrity sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng== - lodash.memoize@4.x: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -6265,11 +6215,6 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.omitby@4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.omitby/-/lodash.omitby-4.6.0.tgz#5c15ff4754ad555016b53c041311e8f079204791" - integrity sha512-5OrRcIVR75M288p4nbI2WLAf3ndw2GD9fyNv3Bc15+WCxJDdZ4lYndSxGd7hnG6PVjiJTeJE2dHEGhIuKGicIQ== - lodash@^4.17.10, lodash@^4.17.13, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -6314,27 +6259,6 @@ lz-string@^1.4.4: resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" integrity sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ== -magic-string@0.30.5: - version "0.30.5" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9" - integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - -magic-string@^0.25.7: - version "0.25.9" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" - integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== - dependencies: - sourcemap-codec "^1.4.8" - -magic-string@^0.30.3: - version "0.30.8" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.8.tgz#14e8624246d2bedba70d5462aa99ac9681844613" - integrity sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -6477,10 +6401,10 @@ node-releases@^2.0.12: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039" integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ== -node-releases@^2.0.18: - version "2.0.18" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" - integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== +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== normalize-path@^3.0.0: version "3.0.0" @@ -6706,11 +6630,6 @@ picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -picomatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" - integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== - pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -6745,16 +6664,16 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== -prettier-plugin-hermes-parser@0.25.1, prettier-plugin-hermes-parser@^0.25.1: - version "0.25.1" - resolved "https://registry.yarnpkg.com/prettier-plugin-hermes-parser/-/prettier-plugin-hermes-parser-0.25.1.tgz#f7e82357f7fdcf5fcdf9e06dcc3bbafe03ed61eb" - integrity sha512-qVsgSt1ZLz7sxQyMmLM3b8JYIcUt4pkE+OCMEoUTe5G87ghNe9lluYMy7ptu1h0f3fAZ+zkifUV3JojMmQcKkg== +prettier-plugin-hermes-parser@0.26.0, prettier-plugin-hermes-parser@^0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/prettier-plugin-hermes-parser/-/prettier-plugin-hermes-parser-0.26.0.tgz#f097ef381c99f624ae491b68ed0e5719b2249caa" + integrity sha512-ajjlx/0OQ+lcZQEnKEUDU7Srr9vw1OoMO6qZDIYmck1u7j9STiCStqb3RG1vE7FripXYAhquuI+oYG8BCTNC4g== dependencies: - hermes-estree "0.25.1" - hermes-parser "0.25.1" - prettier-plugin-hermes-parser "0.25.1" + hermes-estree "0.26.0" + hermes-parser "0.26.0" + prettier-plugin-hermes-parser "0.26.0" -prettier@*, prettier@^3.3.3: +prettier@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== @@ -6857,13 +6776,6 @@ 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" @@ -7000,7 +6912,7 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.14.2, resolve@^1.22.1: +resolve@^1.14.2: version "1.22.2" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== @@ -7038,51 +6950,6 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" -rollup-plugin-banner2@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/rollup-plugin-banner2/-/rollup-plugin-banner2-1.2.3.tgz#4aa454e41a80623180164625368ec0321641a0ef" - integrity sha512-lhpPoDTRZMIvSK1AppGNDIZ4fnQuW4WuENuswSUzvXhTR596zWNOmCaCYoqD15QixnjnG+wT+jauLEK5qGRPZg== - dependencies: - magic-string "^0.25.7" - -rollup-plugin-prettier@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/rollup-plugin-prettier/-/rollup-plugin-prettier-4.1.1.tgz#eb74bd47c3cc3ba68bdf34b5323d0d7a47be8cec" - integrity sha512-ugpi/EqW12yJa4NO3o4f/wt/YHwiQovVGC2jxZgxuKO9osjt4lVxVA427+itl87XmQc6089ZkpDc6OpaOZKWgQ== - dependencies: - "@types/prettier" "^1.0.0 || ^2.0.0 || ^3.0.0" - diff "5.1.0" - lodash.hasin "4.5.2" - lodash.isempty "4.4.0" - lodash.isnil "4.0.0" - lodash.omitby "4.6.0" - magic-string "0.30.5" - -rollup@^4.22.4: - version "4.22.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.22.4.tgz#4135a6446671cd2a2453e1ad42a45d5973ec3a0f" - integrity sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A== - dependencies: - "@types/estree" "1.0.5" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.22.4" - "@rollup/rollup-android-arm64" "4.22.4" - "@rollup/rollup-darwin-arm64" "4.22.4" - "@rollup/rollup-darwin-x64" "4.22.4" - "@rollup/rollup-linux-arm-gnueabihf" "4.22.4" - "@rollup/rollup-linux-arm-musleabihf" "4.22.4" - "@rollup/rollup-linux-arm64-gnu" "4.22.4" - "@rollup/rollup-linux-arm64-musl" "4.22.4" - "@rollup/rollup-linux-powerpc64le-gnu" "4.22.4" - "@rollup/rollup-linux-riscv64-gnu" "4.22.4" - "@rollup/rollup-linux-s390x-gnu" "4.22.4" - "@rollup/rollup-linux-x64-gnu" "4.22.4" - "@rollup/rollup-linux-x64-musl" "4.22.4" - "@rollup/rollup-win32-arm64-msvc" "4.22.4" - "@rollup/rollup-win32-ia32-msvc" "4.22.4" - "@rollup/rollup-win32-x64-msvc" "4.22.4" - fsevents "~2.3.2" - rrweb-cssom@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" @@ -7102,16 +6969,16 @@ rxjs@^7.0.0, rxjs@^7.8.1: dependencies: tslib "^2.1.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.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: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -7163,13 +7030,6 @@ semver@^7.6.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -serialize-javascript@^6.0.1: - 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" - set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -7219,11 +7079,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -smob@^1.0.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/smob/-/smob-1.5.0.tgz#85d79a1403abf128d24d3ebc1cdc5e1a9548d3ab" - integrity sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig== - source-map-support@0.5.13: version "0.5.13" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" @@ -7232,7 +7087,7 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.5.16, source-map-support@~0.5.20: +source-map-support@^0.5.16: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -7250,11 +7105,6 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -sourcemap-codec@^1.4.8: - version "1.4.8" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - spawn-command@^0.0.2-1: version "0.0.2-1" resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" @@ -7397,16 +7247,6 @@ terminal-link@^2.0.0: ansi-escapes "^4.2.1" supports-hyperlinks "^2.0.0" -terser@^5.17.4: - version "5.30.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.30.2.tgz#79fc2222c241647cea54ab928ac987ffbe8ce9e2" - integrity sha512-vTDjRKYKip4dOFL5VizdoxHTYDfEXPdz5t+FbxCC5Rp2s+KbEO8w5wqMDPgj7CtFKZuzq7PXv28fZoXfqqBVuw== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" diff --git a/packages/react-dom/src/__tests__/CSSPropertyOperations-test.js b/packages/react-dom/src/__tests__/CSSPropertyOperations-test.js index bda95b8434d46..b5671cf759cef 100644 --- a/packages/react-dom/src/__tests__/CSSPropertyOperations-test.js +++ b/packages/react-dom/src/__tests__/CSSPropertyOperations-test.js @@ -13,6 +13,8 @@ const React = require('react'); const ReactDOMClient = require('react-dom/client'); const ReactDOMServer = require('react-dom/server'); const act = require('internal-test-utils').act; +const assertConsoleErrorDev = + require('internal-test-utils').assertConsoleErrorDev; describe('CSSPropertyOperations', () => { it('should automatically append `px` to relevant styles', () => { @@ -103,15 +105,14 @@ describe('CSSPropertyOperations', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Unsupported style property background-color. Did you mean backgroundColor?' + '\n in div (at **)' + '\n in Comp (at **)', - ); + ]); }); it('should warn when updating hyphenated style names', async () => { @@ -132,11 +133,10 @@ describe('CSSPropertyOperations', () => { await act(() => { root.render(); }); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev([ + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Unsupported style property -ms-transform. Did you mean msTransform?' + '\n in div (at **)' + '\n in Comp (at **)', @@ -165,11 +165,10 @@ describe('CSSPropertyOperations', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev([ + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ // msTransform is correct already and shouldn't warn 'Unsupported vendor-prefixed style property oTransform. ' + 'Did you mean OTransform?' + @@ -202,11 +201,10 @@ describe('CSSPropertyOperations', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev([ + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ "Style property values shouldn't contain a semicolon. " + 'Try "backgroundColor: blue" instead.' + '\n in div (at **)' + @@ -229,15 +227,14 @@ describe('CSSPropertyOperations', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ '`NaN` is an invalid value for the `fontSize` css style property.' + '\n in div (at **)' + '\n in Comp (at **)', - ); + ]); }); it('should not warn when setting CSS custom properties', async () => { @@ -265,15 +262,14 @@ describe('CSSPropertyOperations', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ '`Infinity` is an invalid value for the `fontSize` css style property.' + '\n in div (at **)' + '\n in Comp (at **)', - ); + ]); }); it('should not add units to CSS custom properties', async () => { diff --git a/packages/react-dom/src/__tests__/DOMPropertyOperations-test.js b/packages/react-dom/src/__tests__/DOMPropertyOperations-test.js index cecc71b45a6c0..ef09e49bf36c1 100644 --- a/packages/react-dom/src/__tests__/DOMPropertyOperations-test.js +++ b/packages/react-dom/src/__tests__/DOMPropertyOperations-test.js @@ -1333,7 +1333,8 @@ describe('DOMPropertyOperations', () => { }); assertConsoleErrorDev([ - 'The `popoverTarget` prop expects the ID of an Element as a string. Received HTMLDivElement {} instead.', + 'The `popoverTarget` prop expects the ID of an Element as a string. Received HTMLDivElement {} instead.\n' + + ' in button (at **)', ]); // Dedupe warning @@ -1375,13 +1376,17 @@ describe('DOMPropertyOperations', () => { expect(container.firstChild.getAttribute('value')).toBe('foo'); } expect(container.firstChild.value).toBe('foo'); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'A component is changing a controlled input to be uncontrolled', - ); + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + 'A component is changing a controlled input to be uncontrolled. ' + + 'This is likely caused by the value changing from a defined to undefined, ' + + 'which should not happen. Decide between using a controlled or uncontrolled ' + + 'input element for the lifetime of the component. ' + + 'More info: https://react.dev/link/controlled-components\n' + + ' in input (at **)', + ]); if (disableInputAttributeSyncing) { expect(container.firstChild.hasAttribute('value')).toBe(false); } else { diff --git a/packages/react-dom/src/__tests__/InvalidEventListeners-test.js b/packages/react-dom/src/__tests__/InvalidEventListeners-test.js index d7045d2756ad4..8bff125c82c32 100644 --- a/packages/react-dom/src/__tests__/InvalidEventListeners-test.js +++ b/packages/react-dom/src/__tests__/InvalidEventListeners-test.js @@ -15,13 +15,14 @@ describe('InvalidEventListeners', () => { let React; let ReactDOMClient; let act; + let assertConsoleErrorDev; let container; beforeEach(() => { jest.resetModules(); React = require('react'); ReactDOMClient = require('react-dom/client'); - act = require('internal-test-utils').act; + ({act, assertConsoleErrorDev} = require('internal-test-utils')); container = document.createElement('div'); document.body.appendChild(container); @@ -34,13 +35,13 @@ describe('InvalidEventListeners', () => { it('should prevent non-function listeners, at dispatch', async () => { const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(
); - }); - }).toErrorDev( - 'Expected `onClick` listener to be a function, instead got a value of `string` type.', - ); + await act(() => { + root.render(
); + }); + assertConsoleErrorDev([ + 'Expected `onClick` listener to be a function, instead got a value of `string` type.\n' + + ' in div (at **)', + ]); const node = container.firstChild; console.error = jest.fn(); diff --git a/packages/react-dom/src/__tests__/ReactChildReconciler-test.js b/packages/react-dom/src/__tests__/ReactChildReconciler-test.js index 1c1475534f3e0..ba0c028fa863a 100644 --- a/packages/react-dom/src/__tests__/ReactChildReconciler-test.js +++ b/packages/react-dom/src/__tests__/ReactChildReconciler-test.js @@ -15,6 +15,7 @@ let React; let ReactDOMClient; let act; +let assertConsoleErrorDev; describe('ReactChildReconciler', () => { beforeEach(() => { @@ -22,7 +23,7 @@ describe('ReactChildReconciler', () => { React = require('react'); ReactDOMClient = require('react-dom/client'); - act = require('internal-test-utils').act; + ({act, assertConsoleErrorDev} = require('internal-test-utils')); }); function createIterable(array) { @@ -62,15 +63,21 @@ describe('ReactChildReconciler', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render( -
-

{iterableFunction}

-
, - ); - }); - }).toErrorDev('Functions are not valid as a React child'); + await act(() => { + root.render( +
+

{iterableFunction}

+
, + ); + }); + assertConsoleErrorDev([ + 'Functions are not valid as a React child. ' + + 'This may happen if you return fn instead of from render. ' + + 'Or maybe you meant to call this function rather than return it.\n' + + '

{fn}

\n' + + ' in h1 (at **)' + + (gate('enableOwnerStacks') ? '' : '\n in div (at **)'), + ]); const node = container.firstChild; expect(node.innerHTML).toContain(''); // h1 @@ -85,16 +92,18 @@ describe('ReactChildReconciler', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'Keys should be unique so that components maintain their identity ' + - 'across updates. Non-unique keys may cause children to be ' + - 'duplicated and/or omitted — the behavior is unsupported and ' + - 'could change in a future version.', - ); + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + 'Encountered two children with the same key, `1`. ' + + 'Keys should be unique so that components maintain their identity across updates. ' + + 'Non-unique keys may cause children to be duplicated and/or omitted — ' + + 'the behavior is unsupported and could change in a future version.\n' + + (gate('enableOwnerStacks') ? '' : ' in div (at **)\n') + + ' in div (at **)\n' + + ' in Component (at **)', + ]); }); it('warns for duplicated array keys with component stack info', async () => { @@ -118,11 +127,10 @@ describe('ReactChildReconciler', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Encountered two children with the same key, `1`. ' + 'Keys should be unique so that components maintain their identity ' + 'across updates. Non-unique keys may cause children to be ' + @@ -135,7 +143,7 @@ describe('ReactChildReconciler', () => { ? '' : ' in Parent (at **)\n') + ' in GrandParent (at **)', - ); + ]); }); it('warns for duplicated iterable keys', async () => { @@ -147,16 +155,19 @@ describe('ReactChildReconciler', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'Keys should be unique so that components maintain their identity ' + + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + 'Encountered two children with the same key, `1`. ' + + 'Keys should be unique so that components maintain their identity ' + 'across updates. Non-unique keys may cause children to be ' + 'duplicated and/or omitted — the behavior is unsupported and ' + - 'could change in a future version.', - ); + 'could change in a future version.\n' + + ' in div (at **)\n' + + (gate(flags => flags.enableOwnerStacks) ? '' : ' in div (at **)\n') + + ' in Component (at **)', + ]); }); it('warns for duplicated iterable keys with component stack info', async () => { @@ -180,11 +191,10 @@ describe('ReactChildReconciler', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Encountered two children with the same key, `1`. ' + 'Keys should be unique so that components maintain their identity ' + 'across updates. Non-unique keys may cause children to be ' + @@ -197,6 +207,6 @@ describe('ReactChildReconciler', () => { ? '' : ' in Parent (at **)\n') + ' in GrandParent (at **)', - ); + ]); }); }); diff --git a/packages/react-dom/src/__tests__/ReactComponent-test.js b/packages/react-dom/src/__tests__/ReactComponent-test.js index 6459114697540..c59ba61e01c44 100644 --- a/packages/react-dom/src/__tests__/ReactComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactComponent-test.js @@ -411,7 +411,9 @@ describe('ReactComponent', () => { assertConsoleErrorDev( [ 'React.jsx: type is invalid -- expected a string (for built-in components) ' + - 'or a class/function (for composite components) but got: undefined.', + 'or a class/function (for composite components) but got: undefined. ' + + "You likely forgot to export your component from the file it's defined in, " + + 'or you might have mixed up default and named imports.', ], {withoutStack: true}, ); @@ -491,16 +493,11 @@ describe('ReactComponent', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect( - expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'React.jsx: type is invalid -- expected a string (for built-in components) ' + - 'or a class/function (for composite components) but got: undefined.', - ), - ).rejects.toThrowError( + await expect(async () => { + await act(() => { + root.render(); + }); + }).rejects.toThrowError( 'Element type is invalid: expected a string (for built-in components) ' + 'or a class/function (for composite components) but got: undefined.' + (__DEV__ @@ -509,6 +506,26 @@ describe('ReactComponent', () => { '\n\nCheck the render method of `Bar`.' : ''), ); + if (!gate('enableOwnerStacks')) { + assertConsoleErrorDev([ + 'React.jsx: type is invalid -- expected a string (for built-in components) ' + + 'or a class/function (for composite components) but got: undefined.' + + (__DEV__ + ? " You likely forgot to export your component from the file it's defined in, " + + 'or you might have mixed up default and named imports.\n' + + ' in Bar (at **)\n' + + ' in Foo (at **)' + : ''), + 'React.jsx: type is invalid -- expected a string (for built-in components) ' + + 'or a class/function (for composite components) but got: undefined.' + + (__DEV__ + ? " You likely forgot to export your component from the file it's defined in, " + + 'or you might have mixed up default and named imports.\n' + + ' in Bar (at **)\n' + + ' in Foo (at **)' + : ''), + ]); + } }); it('throws if a plain object is used as a child', async () => { @@ -624,17 +641,16 @@ describe('ReactComponent', () => { } const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Functions are not valid as a React child. This may happen if ' + 'you return Foo instead of from render. ' + 'Or maybe you meant to call this function rather than return it.\n' + ' {Foo}\n' + ' in Foo (at **)', - ); + ]); }); it('warns on function as a return value from a class', async () => { @@ -644,19 +660,18 @@ describe('ReactComponent', () => { } } const container = document.createElement('div'); - await expect(async () => { - const root = ReactDOMClient.createRoot(container); + const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Functions are not valid as a React child. This may happen if ' + 'you return Foo instead of from render. ' + 'Or maybe you meant to call this function rather than return it.\n' + ' {Foo}\n' + ' in Foo (at **)', - ); + ]); }); it('warns on function as a child to host component', async () => { @@ -669,11 +684,10 @@ describe('ReactComponent', () => { } const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Functions are not valid as a React child. This may happen if ' + 'you return Foo instead of from render. ' + 'Or maybe you meant to call this function rather than return it.\n' + @@ -683,7 +697,7 @@ describe('ReactComponent', () => { ? '' : ' in div (at **)\n') + ' in Foo (at **)', - ); + ]); }); it('does not warn for function-as-a-child that gets resolved', async () => { @@ -724,11 +738,10 @@ describe('ReactComponent', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); let component; - await expect(async () => { - await act(() => { - root.render( (component = current)} />); - }); - }).toErrorDev([ + await act(() => { + root.render( (component = current)} />); + }); + assertConsoleErrorDev([ 'Functions are not valid as a React child. This may happen if ' + 'you return Foo instead of from render. ' + 'Or maybe you meant to call this function rather than return it.\n' + diff --git a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js index 428dac1f1ea9e..75e4cebe80610 100644 --- a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js +++ b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js @@ -14,6 +14,8 @@ let act; let React; let ReactDOM; let ReactDOMClient; +let assertConsoleErrorDev; +let assertConsoleWarnDev; const clone = function (o) { return JSON.parse(JSON.stringify(o)); @@ -90,7 +92,11 @@ describe('ReactComponentLifeCycle', () => { beforeEach(() => { jest.resetModules(); - act = require('internal-test-utils').act; + ({ + act, + assertConsoleErrorDev, + assertConsoleWarnDev, + } = require('internal-test-utils')); React = require('react'); ReactDOM = require('react-dom'); @@ -239,15 +245,15 @@ describe('ReactComponentLifeCycle', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'StatefulComponent: It is not recommended to assign props directly to state ' + "because updates to props won't be reflected in state. " + - 'In most cases, it is better to use props directly.', - ); + 'In most cases, it is better to use props directly.\n' + + ' in StatefulComponent (at **)', + ]); }); it('should not allow update state inside of getInitialState', async () => { @@ -266,16 +272,16 @@ describe('ReactComponentLifeCycle', () => { let container = document.createElement('div'); let root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ "Can't call setState on a component that is not yet mounted. " + 'This is a no-op, but it might indicate a bug in your application. ' + 'Instead, assign to `this.state` directly or define a `state = {};` ' + - 'class property with the desired state in the StatefulComponent component.', - ); + 'class property with the desired state in the StatefulComponent component.\n' + + ' in StatefulComponent (at **)', + ]); container = document.createElement('div'); root = ReactDOMClient.createRoot(container); @@ -308,11 +314,17 @@ describe('ReactComponentLifeCycle', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(element); - }); - }).toErrorDev('Component is accessing isMounted inside its render()'); + await act(() => { + root.render(element); + }); + assertConsoleErrorDev([ + 'Component is accessing isMounted inside its render() function. ' + + 'render() should be a pure function of props and state. ' + + 'It should never access something that requires stale data ' + + 'from the previous render, such as refs. ' + + 'Move this logic to componentDidMount and componentDidUpdate instead.\n' + + ' in Component (at **)', + ]); expect(instance._isMounted()).toBeTruthy(); }); @@ -340,11 +352,17 @@ describe('ReactComponentLifeCycle', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(element); - }); - }).toErrorDev('Component is accessing isMounted inside its render()'); + await act(() => { + root.render(element); + }); + assertConsoleErrorDev([ + 'Component is accessing isMounted inside its render() function. ' + + 'render() should be a pure function of props and state. ' + + 'It should never access something that requires stale data ' + + 'from the previous render, such as refs. ' + + 'Move this logic to componentDidMount and componentDidUpdate instead.\n' + + ' in Component (at **)', + ]); expect(instance._isMounted()).toBeTruthy(); }); @@ -390,11 +408,17 @@ describe('ReactComponentLifeCycle', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev('Component is accessing findDOMNode inside its render()'); + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + 'Component is accessing findDOMNode inside its render(). ' + + 'render() should be a pure function of props and state. ' + + 'It should never access something that requires stale data ' + + 'from the previous render, such as refs. ' + + 'Move this logic to componentDidMount and componentDidUpdate instead.\n' + + ' in Component (at **)', + ]); }); it('should carry through each of the phases of setup', async () => { @@ -453,13 +477,17 @@ describe('ReactComponentLifeCycle', () => { const root = ReactDOMClient.createRoot(document.createElement('div')); const instanceRef = React.createRef(); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'LifeCycleComponent is accessing isMounted inside its render() function', - ); + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + 'LifeCycleComponent is accessing isMounted inside its render() function. ' + + 'render() should be a pure function of props and state. ' + + 'It should never access something that requires stale data ' + + 'from the previous render, such as refs. ' + + 'Move this logic to componentDidMount and componentDidUpdate instead.\n' + + ' in LifeCycleComponent (at **)', + ]); const instance = instanceRef.current; // getInitialState @@ -781,19 +809,45 @@ describe('ReactComponentLifeCycle', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - await expect(async () => { - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'Unsafe legacy lifecycles will not be called for components using new component APIs.', - ); - }).toWarnDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + + 'Component uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' + + ' componentWillMount\n' + + ' componentWillReceiveProps\n' + + ' componentWillUpdate\n\n' + + 'The above lifecycles should be removed. Learn more about this warning here:\n' + + 'https://react.dev/link/unsafe-component-lifecycles\n' + + ' in Component (at **)', + ]); + assertConsoleWarnDev( [ - 'componentWillMount has been renamed', - 'componentWillReceiveProps has been renamed', - 'componentWillUpdate has been renamed', + 'componentWillMount has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' + + '* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: Component', + 'componentWillReceiveProps has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move data fetching code or side effects to componentDidUpdate.\n' + + "* If you're updating state whenever props change, refactor your code to use " + + 'memoization techniques or move it to static getDerivedStateFromProps. ' + + 'Learn more at: https://react.dev/link/derived-state\n' + + '* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: Component', + 'componentWillUpdate has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move data fetching code or side effects to componentDidUpdate.\n' + + '* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: Component', ], {withoutStack: true}, ); @@ -821,20 +875,45 @@ describe('ReactComponentLifeCycle', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - await expect(async () => { - await expect( - async () => - await act(() => { - root.render(); - }), - ).toErrorDev( - 'Unsafe legacy lifecycles will not be called for components using new component APIs.', - ); - }).toWarnDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + + 'Component uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' + + ' componentWillMount\n' + + ' componentWillReceiveProps\n' + + ' componentWillUpdate\n\n' + + 'The above lifecycles should be removed. Learn more about this warning here:\n' + + 'https://react.dev/link/unsafe-component-lifecycles\n' + + ' in Component (at **)', + ]); + assertConsoleWarnDev( [ - 'componentWillMount has been renamed', - 'componentWillReceiveProps has been renamed', - 'componentWillUpdate has been renamed', + 'componentWillMount has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' + + '* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: Component', + 'componentWillReceiveProps has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move data fetching code or side effects to componentDidUpdate.\n' + + "* If you're updating state whenever props change, refactor your code to use " + + 'memoization techniques or move it to static getDerivedStateFromProps. ' + + 'Learn more at: https://react.dev/link/derived-state\n' + + '* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: Component', + 'componentWillUpdate has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move data fetching code or side effects to componentDidUpdate.\n' + + '* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: Component', ], {withoutStack: true}, ); @@ -865,14 +944,19 @@ describe('ReactComponentLifeCycle', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - await expect( - async () => - await act(() => { - root.render(); - }), - ).toErrorDev( - 'Unsafe legacy lifecycles will not be called for components using new component APIs.', - ); + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + + 'Component uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' + + ' UNSAFE_componentWillMount\n' + + ' UNSAFE_componentWillReceiveProps\n' + + ' UNSAFE_componentWillUpdate\n\n' + + 'The above lifecycles should be removed. Learn more about this warning here:\n' + + 'https://react.dev/link/unsafe-component-lifecycles\n' + + ' in Component (at **)', + ]); await act(() => { root.render(); }); @@ -893,24 +977,35 @@ describe('ReactComponentLifeCycle', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - await expect(async () => { - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + - 'AllLegacyLifecycles uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' + - ' componentWillMount\n' + - ' UNSAFE_componentWillReceiveProps\n' + - ' componentWillUpdate\n\n' + - 'The above lifecycles should be removed. Learn more about this warning here:\n' + - 'https://react.dev/link/unsafe-component-lifecycles', - ); - }).toWarnDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + + 'AllLegacyLifecycles uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' + + ' componentWillMount\n' + + ' UNSAFE_componentWillReceiveProps\n' + + ' componentWillUpdate\n\n' + + 'The above lifecycles should be removed. Learn more about this warning here:\n' + + 'https://react.dev/link/unsafe-component-lifecycles\n' + + ' in AllLegacyLifecycles (at **)', + ]); + assertConsoleWarnDev( [ - 'componentWillMount has been renamed', - 'componentWillUpdate has been renamed', + 'componentWillMount has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' + + '* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: AllLegacyLifecycles', + 'componentWillUpdate has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move data fetching code or side effects to componentDidUpdate.\n' + + '* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: AllLegacyLifecycles', ], {withoutStack: true}, ); @@ -926,17 +1021,17 @@ describe('ReactComponentLifeCycle', () => { } } - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + 'WillMount uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' + ' UNSAFE_componentWillMount\n\n' + 'The above lifecycles should be removed. Learn more about this warning here:\n' + - 'https://react.dev/link/unsafe-component-lifecycles', - ); + 'https://react.dev/link/unsafe-component-lifecycles\n' + + ' in WillMount (at **)', + ]); class WillMountAndUpdate extends React.Component { state = {}; @@ -950,23 +1045,30 @@ describe('ReactComponentLifeCycle', () => { } } - await expect(async () => { - await expect( - async () => - await act(() => { - root.render(); - }), - ).toErrorDev( - 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + - 'WillMountAndUpdate uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' + - ' componentWillMount\n' + - ' UNSAFE_componentWillUpdate\n\n' + - 'The above lifecycles should be removed. Learn more about this warning here:\n' + - 'https://react.dev/link/unsafe-component-lifecycles', - ); - }).toWarnDev(['componentWillMount has been renamed'], { - withoutStack: true, + await act(() => { + root.render(); }); + assertConsoleErrorDev([ + 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + + 'WillMountAndUpdate uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' + + ' componentWillMount\n' + + ' UNSAFE_componentWillUpdate\n\n' + + 'The above lifecycles should be removed. Learn more about this warning here:\n' + + 'https://react.dev/link/unsafe-component-lifecycles\n' + + ' in WillMountAndUpdate (at **)', + ]); + assertConsoleWarnDev( + [ + 'componentWillMount has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' + + '* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: WillMountAndUpdate', + ], + {withoutStack: true}, + ); class WillReceiveProps extends React.Component { state = {}; @@ -979,21 +1081,34 @@ describe('ReactComponentLifeCycle', () => { } } - await expect(async () => { - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + - 'WillReceiveProps uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' + - ' componentWillReceiveProps\n\n' + - 'The above lifecycles should be removed. Learn more about this warning here:\n' + - 'https://react.dev/link/unsafe-component-lifecycles', - ); - }).toWarnDev(['componentWillReceiveProps has been renamed'], { - withoutStack: true, + await act(() => { + root.render(); }); + assertConsoleErrorDev([ + 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + + 'WillReceiveProps uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' + + ' componentWillReceiveProps\n\n' + + 'The above lifecycles should be removed. Learn more about this warning here:\n' + + 'https://react.dev/link/unsafe-component-lifecycles\n' + + ' in WillReceiveProps (at **)', + ]); + assertConsoleWarnDev( + [ + 'componentWillReceiveProps has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move data fetching code or side effects to componentDidUpdate.\n' + + "* If you're updating state whenever props change, refactor your code to use " + + 'memoization techniques or move it to static getDerivedStateFromProps. ' + + 'Learn more at: https://react.dev/link/derived-state\n' + + '* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: WillReceiveProps', + ], + { + withoutStack: true, + }, + ); }); it('should warn about deprecated lifecycles (cWM/cWRP/cWU) if new getSnapshotBeforeUpdate is present', async () => { @@ -1010,24 +1125,35 @@ describe('ReactComponentLifeCycle', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - await expect(async () => { - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + - 'AllLegacyLifecycles uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' + - ' componentWillMount\n' + - ' UNSAFE_componentWillReceiveProps\n' + - ' componentWillUpdate\n\n' + - 'The above lifecycles should be removed. Learn more about this warning here:\n' + - 'https://react.dev/link/unsafe-component-lifecycles', - ); - }).toWarnDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + + 'AllLegacyLifecycles uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' + + ' componentWillMount\n' + + ' UNSAFE_componentWillReceiveProps\n' + + ' componentWillUpdate\n\n' + + 'The above lifecycles should be removed. Learn more about this warning here:\n' + + 'https://react.dev/link/unsafe-component-lifecycles\n' + + ' in AllLegacyLifecycles (at **)', + ]); + assertConsoleWarnDev( [ - 'componentWillMount has been renamed', - 'componentWillUpdate has been renamed', + 'componentWillMount has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' + + '* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: AllLegacyLifecycles', + 'componentWillUpdate has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move data fetching code or side effects to componentDidUpdate.\n' + + '* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: AllLegacyLifecycles', ], {withoutStack: true}, ); @@ -1042,17 +1168,17 @@ describe('ReactComponentLifeCycle', () => { } } - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + 'WillMount uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' + ' UNSAFE_componentWillMount\n\n' + 'The above lifecycles should be removed. Learn more about this warning here:\n' + - 'https://react.dev/link/unsafe-component-lifecycles', - ); + 'https://react.dev/link/unsafe-component-lifecycles\n' + + ' in WillMount (at **)', + ]); class WillMountAndUpdate extends React.Component { state = {}; @@ -1065,22 +1191,32 @@ describe('ReactComponentLifeCycle', () => { } } - await expect(async () => { - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + - 'WillMountAndUpdate uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' + - ' componentWillMount\n' + - ' UNSAFE_componentWillUpdate\n\n' + - 'The above lifecycles should be removed. Learn more about this warning here:\n' + - 'https://react.dev/link/unsafe-component-lifecycles', - ); - }).toWarnDev(['componentWillMount has been renamed'], { - withoutStack: true, + await act(() => { + root.render(); }); + assertConsoleErrorDev([ + 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + + 'WillMountAndUpdate uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' + + ' componentWillMount\n' + + ' UNSAFE_componentWillUpdate\n\n' + + 'The above lifecycles should be removed. Learn more about this warning here:\n' + + 'https://react.dev/link/unsafe-component-lifecycles\n' + + ' in WillMountAndUpdate (at **)', + ]); + assertConsoleWarnDev( + [ + 'componentWillMount has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' + + '* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: WillMountAndUpdate', + ], + { + withoutStack: true, + }, + ); class WillReceiveProps extends React.Component { state = {}; @@ -1092,22 +1228,34 @@ describe('ReactComponentLifeCycle', () => { } } - await expect(async () => { - await expect( - async () => - await act(() => { - root.render(); - }), - ).toErrorDev( - 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + - 'WillReceiveProps uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' + - ' componentWillReceiveProps\n\n' + - 'The above lifecycles should be removed. Learn more about this warning here:\n' + - 'https://react.dev/link/unsafe-component-lifecycles', - ); - }).toWarnDev(['componentWillReceiveProps has been renamed'], { - withoutStack: true, + await act(() => { + root.render(); }); + assertConsoleErrorDev([ + 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + + 'WillReceiveProps uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' + + ' componentWillReceiveProps\n\n' + + 'The above lifecycles should be removed. Learn more about this warning here:\n' + + 'https://react.dev/link/unsafe-component-lifecycles\n' + + ' in WillReceiveProps (at **)', + ]); + assertConsoleWarnDev( + [ + 'componentWillReceiveProps has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move data fetching code or side effects to componentDidUpdate.\n' + + "* If you're updating state whenever props change, refactor your code to use " + + 'memoization techniques or move it to static getDerivedStateFromProps. ' + + 'Learn more at: https://react.dev/link/derived-state\n' + + '* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: WillReceiveProps', + ], + { + withoutStack: true, + }, + ); }); it('should warn if getDerivedStateFromProps returns undefined', async () => { @@ -1120,14 +1268,14 @@ describe('ReactComponentLifeCycle', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'MyComponent.getDerivedStateFromProps(): A valid state object (or null) must ' + - 'be returned. You have returned undefined.', - ); + 'be returned. You have returned undefined.\n' + + ' in MyComponent (at **)', + ]); // De-duped await act(() => { @@ -1146,16 +1294,16 @@ describe('ReactComponentLifeCycle', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ '`MyComponent` uses `getDerivedStateFromProps` but its initial state is ' + 'undefined. This is not recommended. Instead, define the initial state by ' + 'assigning an object to `this.state` in the constructor of `MyComponent`. ' + - 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', - ); + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.\n' + + ' in MyComponent (at **)', + ]); // De-duped await act(() => { @@ -1191,15 +1339,35 @@ describe('ReactComponentLifeCycle', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toWarnDev( + await act(() => { + root.render(); + }); + assertConsoleWarnDev( [ - 'componentWillMount has been renamed', - 'componentWillReceiveProps has been renamed', - 'componentWillUpdate has been renamed', + 'componentWillMount has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' + + '* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: MyComponent', + 'componentWillReceiveProps has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move data fetching code or side effects to componentDidUpdate.\n' + + "* If you're updating state whenever props change, refactor your code to use " + + 'memoization techniques or move it to static getDerivedStateFromProps. ' + + 'Learn more at: https://react.dev/link/derived-state\n' + + '* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: MyComponent', + 'componentWillUpdate has been renamed, and is not recommended for use. ' + + 'See https://react.dev/link/unsafe-component-lifecycles for details.\n\n' + + '* Move data fetching code or side effects to componentDidUpdate.\n' + + '* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress this warning in non-strict mode. ' + + 'In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, ' + + 'you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n\n' + + 'Please update the following components: MyComponent', ], {withoutStack: true}, ); @@ -1444,14 +1612,14 @@ describe('ReactComponentLifeCycle', () => { root.render(); }); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'MyComponent.getSnapshotBeforeUpdate(): A snapshot value (or null) must ' + - 'be returned. You have returned undefined.', - ); + 'be returned. You have returned undefined.\n' + + ' in MyComponent (at **)', + ]); // De-duped await act(() => { @@ -1470,14 +1638,14 @@ describe('ReactComponentLifeCycle', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'MyComponent: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). ' + - 'This component defines getSnapshotBeforeUpdate() only.', - ); + 'This component defines getSnapshotBeforeUpdate() only.\n' + + ' in MyComponent (at **)', + ]); // De-duped await act(() => { @@ -1497,11 +1665,10 @@ describe('ReactComponentLifeCycle', () => { const root = ReactDOMClient.createRoot(document.createElement('div')); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toWarnDev( + await act(() => { + root.render(); + }); + assertConsoleWarnDev( [ `componentWillMount has been renamed, and is not recommended for use. See https://react.dev/link/unsafe-component-lifecycles for details. diff --git a/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js b/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js index 30b5ced5cf2e3..3d5f61c1ed520 100644 --- a/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js @@ -18,6 +18,7 @@ let ReactSharedInternals; let Scheduler; let assertLog; let act; +let assertConsoleErrorDev; describe('ReactCompositeComponent', () => { const hasOwnProperty = Object.prototype.hasOwnProperty; @@ -71,7 +72,7 @@ describe('ReactCompositeComponent', () => { require('react').__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; Scheduler = require('scheduler'); assertLog = require('internal-test-utils').assertLog; - act = require('internal-test-utils').act; + ({act, assertConsoleErrorDev} = require('internal-test-utils')); }); describe('MorphingComponent', () => { @@ -308,16 +309,16 @@ describe('ReactCompositeComponent', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ "Can't call forceUpdate on a component that is not yet mounted. " + 'This is a no-op, but it might indicate a bug in your application. ' + 'Instead, assign to `this.state` directly or define a `state = {};` ' + - 'class property with the desired state in the MyComponent component.', - ); + 'class property with the desired state in the MyComponent component.\n' + + ' in MyComponent (at **)', + ]); // No additional warning should be recorded const container2 = document.createElement('div'); @@ -342,16 +343,16 @@ describe('ReactCompositeComponent', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ "Can't call setState on a component that is not yet mounted. " + 'This is a no-op, but it might indicate a bug in your application. ' + 'Instead, assign to `this.state` directly or define a `state = {};` ' + - 'class property with the desired state in the MyComponent component.', - ); + 'class property with the desired state in the MyComponent component.\n' + + ' in MyComponent (at **)', + ]); // No additional warning should be recorded const container2 = document.createElement('div'); @@ -478,16 +479,16 @@ describe('ReactCompositeComponent', () => { } const root = ReactDOMClient.createRoot(container); await expect(async () => { - await expect(async () => { - await act(() => { - root.render(); - }); - }).rejects.toThrow(TypeError); - }).toErrorDev( + await act(() => { + root.render(); + }); + }).rejects.toThrow(TypeError); + assertConsoleErrorDev([ 'The component appears to have a render method, ' + "but doesn't extend React.Component. This is likely to cause errors. " + - 'Change ClassWithRenderNotExtended to extend React.Component instead.', - ); + 'Change ClassWithRenderNotExtended to extend React.Component instead.\n' + + ' in ClassWithRenderNotExtended (at **)', + ]); // Test deduplication await expect(async () => { @@ -514,14 +515,14 @@ describe('ReactCompositeComponent', () => { let instance; const root = ReactDOMClient.createRoot(container); - expect(() => { - ReactDOM.flushSync(() => { - root.render( (instance = ref)} />); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + root.render( (instance = ref)} />); + }); + assertConsoleErrorDev([ 'Cannot update during an existing state transition (such as within ' + - '`render`). Render methods should be a pure function of props and state.', - ); + '`render`). Render methods should be a pure function of props and state.\n' + + ' in Component (at **)', + ]); // The setState call is queued and then executed as a second pass. This // behavior is undefined though so we're free to change it to suit the @@ -618,14 +619,14 @@ describe('ReactCompositeComponent', () => { root.render( (instance = ref)} />); }); - expect(() => { - ReactDOM.flushSync(() => { - instance.setState({bogus: true}); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + instance.setState({bogus: true}); + }); + assertConsoleErrorDev([ 'ClassComponent.shouldComponentUpdate(): Returned undefined instead of a ' + - 'boolean value. Make sure to return true or false.', - ); + 'boolean value. Make sure to return true or false.\n' + + ' in ClassComponent (at **)', + ]); }); it('should warn when componentDidUnmount method is defined', async () => { @@ -638,15 +639,15 @@ describe('ReactCompositeComponent', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Component has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + - 'Did you mean componentWillUnmount()?', - ); + 'Did you mean componentWillUnmount()?\n' + + ' in Component (at **)', + ]); }); it('should warn when componentDidReceiveProps method is defined', () => { @@ -660,17 +661,17 @@ describe('ReactCompositeComponent', () => { const root = ReactDOMClient.createRoot(document.createElement('div')); - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Component has a method called ' + 'componentDidReceiveProps(). But there is no such lifecycle method. ' + 'If you meant to update the state in response to changing props, ' + 'use componentWillReceiveProps(). If you meant to fetch data or ' + - 'run side-effects or mutations after React has updated the UI, use componentDidUpdate().', - ); + 'run side-effects or mutations after React has updated the UI, use componentDidUpdate().\n' + + ' in Component (at **)', + ]); }); it('should warn when defaultProps was defined as an instance property', () => { @@ -686,14 +687,14 @@ describe('ReactCompositeComponent', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Setting defaultProps as an instance property on Component is not supported ' + - 'and will be ignored. Instead, define defaultProps as a static property on Component.', - ); + 'and will be ignored. Instead, define defaultProps as a static property on Component.\n' + + ' in Component (at **)', + ]); }); it('should skip update when rerendering element in container', async () => { @@ -739,16 +740,16 @@ describe('ReactCompositeComponent', () => { } } - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Render methods should be a pure function of props and state; ' + 'triggering nested component updates from render is not allowed. If ' + - 'necessary, trigger nested updates in componentDidUpdate.\n\nCheck the ' + - 'render method of Outer.', - ); + 'necessary, trigger nested updates in componentDidUpdate.\n\n' + + 'Check the render method of Outer.\n' + + ' in Outer (at **)', + ]); }); it('only renders once if updated in componentWillReceiveProps', async () => { @@ -836,14 +837,14 @@ describe('ReactCompositeComponent', () => { } const root = ReactDOMClient.createRoot(container); - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ 'When calling super() in `Foo`, make sure to pass ' + - "up the same props that your component's constructor was passed.", - ); + "up the same props that your component's constructor was passed.\n" + + ' in Foo (at **)', + ]); }); it('should only call componentWillUnmount once', async () => { @@ -1185,16 +1186,17 @@ describe('ReactCompositeComponent', () => { const root = ReactDOMClient.createRoot(document.createElement('div')); await expect(async () => { - await expect(async () => { - await act(() => { - root.render(); - }); - }).rejects.toThrow(); - }).toErrorDev([ + await act(() => { + root.render(); + }); + }).rejects.toThrow(); + assertConsoleErrorDev([ 'No `render` method found on the RenderTextInvalidConstructor instance: ' + - 'did you accidentally return an object from the constructor?', + 'did you accidentally return an object from the constructor?\n' + + ' in RenderTextInvalidConstructor (at **)', 'No `render` method found on the RenderTextInvalidConstructor instance: ' + - 'did you accidentally return an object from the constructor?', + 'did you accidentally return an object from the constructor?\n' + + ' in RenderTextInvalidConstructor (at **)', ]); }); @@ -1210,14 +1212,14 @@ describe('ReactCompositeComponent', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ 'It looks like Bad is reassigning its own `this.props` while rendering. ' + - 'This is not supported and can lead to confusing bugs.', - ); + 'This is not supported and can lead to confusing bugs.\n' + + ' in Bad (at **)', + ]); }); it('should return error if render is not defined', async () => { @@ -1225,16 +1227,17 @@ describe('ReactCompositeComponent', () => { const root = ReactDOMClient.createRoot(document.createElement('div')); await expect(async () => { - await expect(async () => { - await act(() => { - root.render(); - }); - }).rejects.toThrow(); - }).toErrorDev([ + await act(() => { + root.render(); + }); + }).rejects.toThrow(); + assertConsoleErrorDev([ 'No `render` method found on the RenderTestUndefinedRender instance: ' + - 'you may have forgotten to define `render`.', + 'you may have forgotten to define `render`.\n' + + ' in RenderTestUndefinedRender (at **)', 'No `render` method found on the RenderTestUndefinedRender instance: ' + - 'you may have forgotten to define `render`.', + 'you may have forgotten to define `render`.\n' + + ' in RenderTestUndefinedRender (at **)', ]); }); @@ -1386,13 +1389,18 @@ describe('ReactCompositeComponent', () => { } const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( - 'Cannot update a component (`A`) while rendering a different component (`B`)', - ); + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ + 'Cannot update a component (`A`) while rendering a different component (`B`). ' + + 'To locate the bad setState() call inside `B`, ' + + 'follow the stack trace as described in https://react.dev/link/setstate-in-render\n' + + (gate('enableOwnerStacks') + ? '' + : ' in B (at **)\n' + ' in div (at **)\n') + + ' in Parent (at **)', + ]); // We error, but still update the state. expect(ref.textContent).toBe('1'); diff --git a/packages/react-dom/src/__tests__/ReactCompositeComponentState-test.js b/packages/react-dom/src/__tests__/ReactCompositeComponentState-test.js index a651a477a8e76..d0d1c36e514a9 100644 --- a/packages/react-dom/src/__tests__/ReactCompositeComponentState-test.js +++ b/packages/react-dom/src/__tests__/ReactCompositeComponentState-test.js @@ -17,13 +17,14 @@ let Scheduler; let assertLog; let TestComponent; let testComponentInstance; +let assertConsoleErrorDev; describe('ReactCompositeComponent-state', () => { beforeEach(() => { React = require('react'); ReactDOM = require('react-dom'); ReactDOMClient = require('react-dom/client'); - act = require('internal-test-utils').act; + ({act, assertConsoleErrorDev} = require('internal-test-utils')); Scheduler = require('scheduler'); const InternalTestUtils = require('internal-test-utils'); @@ -469,15 +470,15 @@ describe('ReactCompositeComponent-state', () => { root.render(); }); // Update - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Test.componentWillReceiveProps(): Assigning directly to ' + "this.state is deprecated (except inside a component's constructor). " + - 'Use setState instead.', - ); + 'Use setState instead.\n' + + ' in Test (at **)', + ]); assertLog([ 'render -- step: 1, extra: true', @@ -518,15 +519,15 @@ describe('ReactCompositeComponent-state', () => { // Mount const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ 'Test.componentWillMount(): Assigning directly to ' + "this.state is deprecated (except inside a component's constructor). " + - 'Use setState instead.', - ); + 'Use setState instead.\n' + + ' in Test (at **)', + ]); assertLog([ 'render -- step: 3, extra: false', @@ -566,13 +567,16 @@ describe('ReactCompositeComponent-state', () => { }); expect(el.textContent).toBe('A'); - expect(() => { - ReactDOM.flushSync(() => { - root.render(); - }); - }).toErrorDev( - "Can't perform a React state update on a component that hasn't mounted yet", - ); + ReactDOM.flushSync(() => { + root.render(); + }); + assertConsoleErrorDev([ + "Can't perform a React state update on a component that hasn't mounted yet. " + + 'This indicates that you have a side-effect in your render function that ' + + 'asynchronously later calls tries to update the component. ' + + 'Move this work to useEffect instead.\n' + + ' in B (at **)', + ]); }); // @gate !disableLegacyMode diff --git a/packages/react-dom/src/__tests__/ReactDOM-test.js b/packages/react-dom/src/__tests__/ReactDOM-test.js index c6c90d1cf15f2..92571ad69e10c 100644 --- a/packages/react-dom/src/__tests__/ReactDOM-test.js +++ b/packages/react-dom/src/__tests__/ReactDOM-test.js @@ -14,7 +14,7 @@ let ReactDOM; let findDOMNode; let ReactDOMClient; let ReactDOMServer; - +let assertConsoleErrorDev; let act; describe('ReactDOM', () => { @@ -28,7 +28,7 @@ describe('ReactDOM', () => { ReactDOM.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE .findDOMNode; - act = require('internal-test-utils').act; + ({act, assertConsoleErrorDev} = require('internal-test-utils')); }); it('should bubble onSubmit', async () => { @@ -188,15 +188,14 @@ describe('ReactDOM', () => { const myDiv = document.createElement('div'); await expect(async () => { - await expect(async () => { - await act(() => { - ReactDOM.render(, myDiv, 'no'); - }); - }).rejects.toThrowError( - 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: no', - ); - }).toErrorDev( + await act(() => { + ReactDOM.render(, myDiv, 'no'); + }); + }).rejects.toThrowError( + 'Invalid argument passed as callback. Expected a function. Instead ' + + 'received: no', + ); + assertConsoleErrorDev( [ 'Expected the last optional `callback` argument to be a function. Instead received: no.', 'Expected the last optional `callback` argument to be a function. Instead received: no.', @@ -205,15 +204,14 @@ describe('ReactDOM', () => { ); await expect(async () => { - await expect(async () => { - await act(() => { - ReactDOM.render(, myDiv, {foo: 'bar'}); - }); - }).rejects.toThrowError( - 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: [object Object]', - ); - }).toErrorDev( + await act(() => { + ReactDOM.render(, myDiv, {foo: 'bar'}); + }); + }).rejects.toThrowError( + 'Invalid argument passed as callback. Expected a function. Instead ' + + 'received: [object Object]', + ); + assertConsoleErrorDev( [ "Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }", "Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }.", @@ -222,15 +220,14 @@ describe('ReactDOM', () => { ); await expect(async () => { - await expect(async () => { - await act(() => { - ReactDOM.render(, myDiv, new Foo()); - }); - }).rejects.toThrowError( - 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: [object Object]', - ); - }).toErrorDev( + await act(() => { + ReactDOM.render(, myDiv, new Foo()); + }); + }).rejects.toThrowError( + 'Invalid argument passed as callback. Expected a function. Instead ' + + 'received: [object Object]', + ); + assertConsoleErrorDev( [ 'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.', 'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.', @@ -257,15 +254,14 @@ describe('ReactDOM', () => { const myDiv = document.createElement('div'); ReactDOM.render(, myDiv); await expect(async () => { - await expect(async () => { - await act(() => { - ReactDOM.render(, myDiv, 'no'); - }); - }).rejects.toThrowError( - 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: no', - ); - }).toErrorDev( + await act(() => { + ReactDOM.render(, myDiv, 'no'); + }); + }).rejects.toThrowError( + 'Invalid argument passed as callback. Expected a function. Instead ' + + 'received: no', + ); + assertConsoleErrorDev( [ 'Expected the last optional `callback` argument to be a function. Instead received: no.', 'Expected the last optional `callback` argument to be a function. Instead received: no.', @@ -275,15 +271,14 @@ describe('ReactDOM', () => { ReactDOM.render(, myDiv); // Re-mount await expect(async () => { - await expect(async () => { - await act(() => { - ReactDOM.render(, myDiv, {foo: 'bar'}); - }); - }).rejects.toThrowError( - 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: [object Object]', - ); - }).toErrorDev( + await act(() => { + ReactDOM.render(, myDiv, {foo: 'bar'}); + }); + }).rejects.toThrowError( + 'Invalid argument passed as callback. Expected a function. Instead ' + + 'received: [object Object]', + ); + assertConsoleErrorDev( [ "Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }.", "Expected the last optional `callback` argument to be a function. Instead received: { foo: 'bar' }.", @@ -293,15 +288,14 @@ describe('ReactDOM', () => { ReactDOM.render(, myDiv); // Re-mount await expect(async () => { - await expect(async () => { - await act(() => { - ReactDOM.render(, myDiv, new Foo()); - }); - }).rejects.toThrowError( - 'Invalid argument passed as callback. Expected a function. Instead ' + - 'received: [object Object]', - ); - }).toErrorDev( + await act(() => { + ReactDOM.render(, myDiv, new Foo()); + }); + }).rejects.toThrowError( + 'Invalid argument passed as callback. Expected a function. Instead ' + + 'received: [object Object]', + ); + assertConsoleErrorDev( [ 'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.', 'Expected the last optional `callback` argument to be a function. Instead received: Foo { a: 1, b: 2 }.', @@ -544,11 +538,10 @@ describe('ReactDOM', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev([ + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ // ReactDOM(App > div > span) 'Invalid ARIA attribute `ariaTypo`. ARIA attributes follow the pattern aria-* and must be lowercase.\n' + ' in span (at **)\n' + diff --git a/packages/react-dom/src/__tests__/ReactDOMAttribute-test.js b/packages/react-dom/src/__tests__/ReactDOMAttribute-test.js index 9b7d9a30cbd53..cd1d055c09d1c 100644 --- a/packages/react-dom/src/__tests__/ReactDOMAttribute-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMAttribute-test.js @@ -13,12 +13,15 @@ describe('ReactDOM unknown attribute', () => { let React; let ReactDOMClient; let act; + let assertConsoleErrorDev; beforeEach(() => { jest.resetModules(); React = require('react'); ReactDOMClient = require('react-dom/client'); act = require('internal-test-utils').act; + assertConsoleErrorDev = + require('internal-test-utils').assertConsoleErrorDev; }); async function testUnknownAttributeRemoval(givenValue) { @@ -62,12 +65,13 @@ describe('ReactDOM unknown attribute', () => { }); it('changes values true, false to null, and also warns once', async () => { - await expect(() => testUnknownAttributeAssignment(true, null)).toErrorDev( + await testUnknownAttributeAssignment(true, null); + assertConsoleErrorDev([ 'Received `true` for a non-boolean attribute `unknown`.\n\n' + 'If you want to write it to the DOM, pass a string instead: ' + 'unknown="true" or unknown={value.toString()}.\n' + ' in div (at **)', - ); + ]); await testUnknownAttributeAssignment(false, null); }); @@ -92,11 +96,9 @@ describe('ReactDOM unknown attribute', () => { const el = document.createElement('div'); const root = ReactDOMClient.createRoot(el); - await expect(async () => { - await act(() => { - root.render(
); - }); - }).toErrorDev([]); + await act(() => { + root.render(
); + }); expect(el.firstChild.getAttribute('inert')).toBe(true ? '' : null); }); @@ -105,15 +107,15 @@ describe('ReactDOM unknown attribute', () => { const el = document.createElement('div'); const root = ReactDOMClient.createRoot(el); - await expect(async () => { - await act(() => { - root.render(
); - }); - }).toErrorDev([ + await act(() => { + root.render(
); + }); + assertConsoleErrorDev([ 'Received an empty string for a boolean attribute `inert`. ' + 'This will treat the attribute as if it were false. ' + 'Either pass `false` to silence this warning, or ' + - 'pass `true` if you used an empty string in earlier versions of React to indicate this attribute is true.', + 'pass `true` if you used an empty string in earlier versions of React to indicate this attribute is true.\n' + + ' in div (at **)', ]); expect(el.firstChild.getAttribute('inert')).toBe(true ? null : ''); @@ -136,11 +138,12 @@ describe('ReactDOM unknown attribute', () => { }); it('coerces NaN to strings and warns', async () => { - await expect(() => testUnknownAttributeAssignment(NaN, 'NaN')).toErrorDev( + await testUnknownAttributeAssignment(NaN, 'NaN'); + assertConsoleErrorDev([ 'Received NaN for the `unknown` attribute. ' + 'If this is expected, cast the value to a string.\n' + ' in div (at **)', - ); + ]); }); it('coerces objects to strings and warns', async () => { @@ -167,52 +170,52 @@ describe('ReactDOM unknown attribute', () => { } const test = () => testUnknownAttributeAssignment(new TemporalLike(), null); - await expect(() => - expect(test).rejects.toThrowError(new TypeError('prod message')), - ).toErrorDev( + + await expect(test).rejects.toThrowError(new TypeError('prod message')); + assertConsoleErrorDev([ 'The provided `unknown` attribute is an unsupported type TemporalLike.' + - ' This value must be coerced to a string before using it here.', - ); + ' This value must be coerced to a string before using it here.\n' + + ' in div (at **)', + ]); }); it('removes symbols and warns', async () => { - await expect(() => testUnknownAttributeRemoval(Symbol('foo'))).toErrorDev( + await testUnknownAttributeRemoval(Symbol('foo')); + assertConsoleErrorDev([ 'Invalid value for prop `unknown` on
tag. Either remove it ' + 'from the element, or pass a string or number value to keep it ' + 'in the DOM. For details, see https://react.dev/link/attribute-behavior \n' + ' in div (at **)', - ); + ]); }); it('removes functions and warns', async () => { - await expect(() => - testUnknownAttributeRemoval(function someFunction() {}), - ).toErrorDev( + await testUnknownAttributeRemoval(function someFunction() {}); + assertConsoleErrorDev([ 'Invalid value for prop `unknown` on
tag. Either remove ' + 'it from the element, or pass a string or number value to ' + 'keep it in the DOM. For details, see ' + 'https://react.dev/link/attribute-behavior \n' + ' in div (at **)', - ); + ]); }); it('allows camelCase unknown attributes and warns', async () => { const el = document.createElement('div'); - await expect(async () => { - const root = ReactDOMClient.createRoot(el); + const root = ReactDOMClient.createRoot(el); - await act(() => { - root.render(
); - }); - }).toErrorDev( + await act(() => { + root.render(
); + }); + assertConsoleErrorDev([ 'React does not recognize the `helloWorld` prop on a DOM element. ' + 'If you intentionally want it to appear in the DOM as a custom ' + 'attribute, spell it as lowercase `helloworld` instead. ' + 'If you accidentally passed it from a parent component, remove ' + 'it from the DOM element.\n' + ' in div (at **)', - ); + ]); expect(el.firstChild.getAttribute('helloworld')).toBe('something'); }); diff --git a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js index ce71a6334ee64..65f82dcd3690a 100644 --- a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js @@ -19,6 +19,7 @@ describe('ReactDOMComponent', () => { let act; let assertLog; let Scheduler; + let assertConsoleErrorDev; beforeEach(() => { jest.resetModules(); @@ -28,6 +29,8 @@ describe('ReactDOMComponent', () => { ReactDOMServer = require('react-dom/server'); Scheduler = require('scheduler'); act = require('internal-test-utils').act; + assertConsoleErrorDev = + require('internal-test-utils').assertConsoleErrorDev; assertLog = require('internal-test-utils').assertLog; }); @@ -189,73 +192,72 @@ describe('ReactDOMComponent', () => { it('should warn for unknown prop', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(
{}} />); - }); - }).toErrorDev( + await act(() => { + root.render(
{}} />); + }); + assertConsoleErrorDev([ 'Invalid value for prop `foo` on
tag. Either remove it ' + 'from the element, or pass a string or number value to keep ' + 'it in the DOM. For details, see https://react.dev/link/attribute-behavior ' + '\n in div (at **)', - ); + ]); }); it('should group multiple unknown prop warnings together', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(
{}} baz={() => {}} />); - }); - }).toErrorDev( + await act(() => { + root.render(
{}} baz={() => {}} />); + }); + assertConsoleErrorDev([ 'Invalid values for props `foo`, `baz` on
tag. Either remove ' + 'them from the element, or pass a string or number value to keep ' + 'them in the DOM. For details, see https://react.dev/link/attribute-behavior ' + '\n in div (at **)', - ); + ]); }); it('should warn for onDblClick prop', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(
{}} />); - }); - }).toErrorDev( - 'Invalid event handler property `onDblClick`. Did you mean `onDoubleClick`?\n in div (at **)', - ); + await act(() => { + root.render(
{}} />); + }); + assertConsoleErrorDev([ + 'Invalid event handler property `onDblClick`. Did you mean `onDoubleClick`?\n' + + ' in div (at **)', + ]); }); it('should warn for unknown string event handlers', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(
); - }); - }).toErrorDev( - 'Unknown event handler property `onUnknown`. It will be ignored.\n in div (at **)', - ); + await act(() => { + root.render(
); + }); + assertConsoleErrorDev([ + 'Unknown event handler property `onUnknown`. It will be ignored.\n' + + ' in div (at **)', + ]); expect(container.firstChild.hasAttribute('onUnknown')).toBe(false); expect(container.firstChild.onUnknown).toBe(undefined); - await expect(async () => { - await act(() => { - root.render(
); - }); - }).toErrorDev( - 'Unknown event handler property `onunknown`. It will be ignored.\n in div (at **)', - ); + await act(() => { + root.render(
); + }); + assertConsoleErrorDev([ + 'Unknown event handler property `onunknown`. It will be ignored.\n' + + ' in div (at **)', + ]); expect(container.firstChild.hasAttribute('onunknown')).toBe(false); expect(container.firstChild.onunknown).toBe(undefined); - await expect(async () => { - await act(() => { - root.render(
); - }); - }).toErrorDev( - 'Unknown event handler property `on-unknown`. It will be ignored.\n in div (at **)', - ); + + await act(() => { + root.render(
); + }); + assertConsoleErrorDev([ + 'Unknown event handler property `on-unknown`. It will be ignored.\n' + + ' in div (at **)', + ]); expect(container.firstChild.hasAttribute('on-unknown')).toBe(false); expect(container.firstChild['on-unknown']).toBe(undefined); }); @@ -263,31 +265,31 @@ describe('ReactDOMComponent', () => { it('should warn for unknown function event handlers', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(
); - }); - }).toErrorDev( - 'Unknown event handler property `onUnknown`. It will be ignored.\n in div (at **)', - ); + await act(() => { + root.render(
); + }); + assertConsoleErrorDev([ + 'Unknown event handler property `onUnknown`. It will be ignored.\n' + + ' in div (at **)', + ]); expect(container.firstChild.hasAttribute('onUnknown')).toBe(false); expect(container.firstChild.onUnknown).toBe(undefined); - await expect(async () => { - await act(() => { - root.render(
); - }); - }).toErrorDev( - 'Unknown event handler property `onunknown`. It will be ignored.\n in div (at **)', - ); + await act(() => { + root.render(
); + }); + assertConsoleErrorDev([ + 'Unknown event handler property `onunknown`. It will be ignored.\n' + + ' in div (at **)', + ]); expect(container.firstChild.hasAttribute('onunknown')).toBe(false); expect(container.firstChild.onunknown).toBe(undefined); - await expect(async () => { - await act(() => { - root.render(
); - }); - }).toErrorDev( - 'Unknown event handler property `on-unknown`. It will be ignored.\n in div (at **)', - ); + await act(() => { + root.render(
); + }); + assertConsoleErrorDev([ + 'Unknown event handler property `on-unknown`. It will be ignored.\n' + + ' in div (at **)', + ]); expect(container.firstChild.hasAttribute('on-unknown')).toBe(false); expect(container.firstChild['on-unknown']).toBe(undefined); }); @@ -295,13 +297,13 @@ describe('ReactDOMComponent', () => { it('should warn for badly cased React attributes', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(
); - }); - }).toErrorDev( - 'Invalid DOM property `CHILDREN`. Did you mean `children`?\n in div (at **)', - ); + await act(() => { + root.render(
); + }); + assertConsoleErrorDev([ + 'Invalid DOM property `CHILDREN`. Did you mean `children`?\n' + + ' in div (at **)', + ]); expect(container.firstChild.getAttribute('CHILDREN')).toBe('5'); }); @@ -323,14 +325,13 @@ describe('ReactDOMComponent', () => { const style = {fontSize: NaN}; const div = document.createElement('div'); const root = ReactDOMClient.createRoot(div); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - '`NaN` is an invalid value for the `fontSize` css style property.' + - '\n in span (at **)', - ); + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + '`NaN` is an invalid value for the `fontSize` css style property.\n' + + ' in span (at **)', + ]); await act(() => { root.render(); }); @@ -350,15 +351,18 @@ describe('ReactDOMComponent', () => { const style = {fontSize: new TemporalLike()}; const root = ReactDOMClient.createRoot(document.createElement('div')); await expect(async () => { - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'The provided `fontSize` CSS property is an unsupported type TemporalLike.' + - ' This value must be coerced to a string before using it here.', - ); + await act(() => { + root.render(); + }); }).rejects.toThrowError(new TypeError('prod message')); + assertConsoleErrorDev([ + 'The provided `fontSize` CSS property is an unsupported type TemporalLike.' + + ' This value must be coerced to a string before using it here.\n' + + ' in span (at **)', + 'The provided `fontSize` CSS property is an unsupported type TemporalLike.' + + ' This value must be coerced to a string before using it here.\n' + + ' in span (at **)', + ]); }); it('should update styles if initially null', async () => { @@ -590,16 +594,16 @@ describe('ReactDOMComponent', () => { it('should not add an empty src attribute', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'An empty string ("") was passed to the src attribute. ' + 'This may cause the browser to download the whole page again over the network. ' + 'To fix this, either do not render the element at all ' + - 'or pass null to src instead of an empty string.', - ); + 'or pass null to src instead of an empty string.\n' + + ' in img (at **)', + ]); const node = container.firstChild; expect(node.hasAttribute('src')).toBe(false); @@ -608,31 +612,31 @@ describe('ReactDOMComponent', () => { }); expect(node.hasAttribute('src')).toBe(true); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'An empty string ("") was passed to the src attribute. ' + 'This may cause the browser to download the whole page again over the network. ' + 'To fix this, either do not render the element at all ' + - 'or pass null to src instead of an empty string.', - ); + 'or pass null to src instead of an empty string.\n' + + ' in img (at **)', + ]); expect(node.hasAttribute('src')).toBe(false); }); it('should not add an empty href attribute', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'An empty string ("") was passed to the href attribute. ' + 'To fix this, either do not render the element at all ' + - 'or pass null to href instead of an empty string.', - ); + 'or pass null to href instead of an empty string.\n' + + ' in link (at **)', + ]); const node = container.firstChild; expect(node.hasAttribute('href')).toBe(false); @@ -641,15 +645,15 @@ describe('ReactDOMComponent', () => { }); expect(node.hasAttribute('href')).toBe(true); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'An empty string ("") was passed to the href attribute. ' + 'To fix this, either do not render the element at all ' + - 'or pass null to href instead of an empty string.', - ); + 'or pass null to href instead of an empty string.\n' + + ' in link (at **)', + ]); expect(node.hasAttribute('href')).toBe(false); }); @@ -871,204 +875,235 @@ describe('ReactDOMComponent', () => { }); it('should reject attribute key injection attack on markup for regular DOM (SSR)', () => { - expect(() => { - for (let i = 0; i < 3; i++) { - const element1 = React.createElement( - 'div', - {'blah" onclick="beevil" noise="hi': 'selected'}, - null, - ); - const element2 = React.createElement( - 'div', - {'>
': 'selected'}, - null, - ); - const result1 = ReactDOMServer.renderToString(element1); - const result2 = ReactDOMServer.renderToString(element2); - expect(result1.toLowerCase()).not.toContain('onclick'); - expect(result2.toLowerCase()).not.toContain('script'); - } - }).toErrorDev([ - 'Invalid attribute name: `blah" onclick="beevil" noise="hi`', - 'Invalid attribute name: `>
`', + for (let i = 0; i < 3; i++) { + const element1 = React.createElement( + 'div', + {'blah" onclick="beevil" noise="hi': 'selected'}, + null, + ); + const element2 = React.createElement( + 'div', + {'>
': 'selected'}, + null, + ); + const result1 = ReactDOMServer.renderToString(element1); + const result2 = ReactDOMServer.renderToString(element2); + expect(result1.toLowerCase()).not.toContain('onclick'); + expect(result2.toLowerCase()).not.toContain('script'); + } + assertConsoleErrorDev([ + 'Invalid attribute name: `blah" onclick="beevil" noise="hi`\n' + + ' in div (at **)', + 'Invalid attribute name: `>
`\n' + + ' in div (at **)', ]); }); it('should reject attribute key injection attack on markup for custom elements (SSR)', () => { - expect(() => { - for (let i = 0; i < 3; i++) { - const element1 = React.createElement( - 'x-foo-component', - {'blah" onclick="beevil" noise="hi': 'selected'}, - null, - ); - const element2 = React.createElement( - 'x-foo-component', - {'>': 'selected'}, - null, - ); - const result1 = ReactDOMServer.renderToString(element1); - const result2 = ReactDOMServer.renderToString(element2); - expect(result1.toLowerCase()).not.toContain('onclick'); - expect(result2.toLowerCase()).not.toContain('script'); - } - }).toErrorDev([ - 'Invalid attribute name: `blah" onclick="beevil" noise="hi`', - 'Invalid attribute name: `>`', + for (let i = 0; i < 3; i++) { + const element1 = React.createElement( + 'x-foo-component', + {'blah" onclick="beevil" noise="hi': 'selected'}, + null, + ); + const element2 = React.createElement( + 'x-foo-component', + {'>': 'selected'}, + null, + ); + const result1 = ReactDOMServer.renderToString(element1); + const result2 = ReactDOMServer.renderToString(element2); + expect(result1.toLowerCase()).not.toContain('onclick'); + expect(result2.toLowerCase()).not.toContain('script'); + } + assertConsoleErrorDev([ + 'Invalid attribute name: `blah" onclick="beevil" noise="hi`\n' + + ' in x-foo-component (at **)', + 'Invalid attribute name: `>`\n' + + ' in x-foo-component (at **)', ]); }); it('should reject attribute key injection attack on mount for regular DOM', async () => { - await expect(async () => { - for (let i = 0; i < 3; i++) { - const container = document.createElement('div'); - let root = ReactDOMClient.createRoot(container); - await act(() => { - root.render( - React.createElement( - 'div', - {'blah" onclick="beevil" noise="hi': 'selected'}, - null, - ), - ); - }); - - expect(container.firstChild.attributes.length).toBe(0); - await act(() => { - root.unmount(); - }); - root = ReactDOMClient.createRoot(container); - await act(() => { - root.render( - React.createElement( - 'div', - {'>
': 'selected'}, - null, - ), - ); - }); - - expect(container.firstChild.attributes.length).toBe(0); + for (let i = 0; i < 3; i++) { + const container = document.createElement('div'); + let root = ReactDOMClient.createRoot(container); + await act(() => { + root.render( + React.createElement( + 'div', + {'blah" onclick="beevil" noise="hi': 'selected'}, + null, + ), + ); + }); + + expect(container.firstChild.attributes.length).toBe(0); + if (i === 0) { + assertConsoleErrorDev([ + 'Invalid attribute name: `blah" onclick="beevil" noise="hi`\n' + + ' in div (at **)', + ]); } - }).toErrorDev([ - 'Invalid attribute name: `blah" onclick="beevil" noise="hi`', - 'Invalid attribute name: `>
`', - ]); + await act(() => { + root.unmount(); + }); + root = ReactDOMClient.createRoot(container); + await act(() => { + root.render( + React.createElement( + 'div', + {'>
': 'selected'}, + null, + ), + ); + }); + if (i === 0) { + assertConsoleErrorDev([ + 'Invalid attribute name: `>
`\n' + + ' in div (at **)', + ]); + } + + expect(container.firstChild.attributes.length).toBe(0); + } }); it('should reject attribute key injection attack on mount for custom elements', async () => { - await expect(async () => { - for (let i = 0; i < 3; i++) { - const container = document.createElement('div'); - let root = ReactDOMClient.createRoot(container); - - await act(() => { - root.render( - React.createElement( - 'x-foo-component', - {'blah" onclick="beevil" noise="hi': 'selected'}, - null, - ), - ); - }); - - expect(container.firstChild.attributes.length).toBe(0); - await act(() => { - root.unmount(); - }); - root = ReactDOMClient.createRoot(container); - await act(() => { - root.render( - React.createElement( - 'x-foo-component', - {'>': 'selected'}, - null, - ), - ); - }); - - expect(container.firstChild.attributes.length).toBe(0); + for (let i = 0; i < 3; i++) { + const container = document.createElement('div'); + let root = ReactDOMClient.createRoot(container); + + await act(() => { + root.render( + React.createElement( + 'x-foo-component', + {'blah" onclick="beevil" noise="hi': 'selected'}, + null, + ), + ); + }); + + if (i === 0) { + assertConsoleErrorDev([ + 'Invalid attribute name: `blah" onclick="beevil" noise="hi`\n' + + ' in x-foo-component (at **)', + ]); } - }).toErrorDev([ - 'Invalid attribute name: `blah" onclick="beevil" noise="hi`', - 'Invalid attribute name: `>`', - ]); + expect(container.firstChild.attributes.length).toBe(0); + await act(() => { + root.unmount(); + }); + + root = ReactDOMClient.createRoot(container); + await act(() => { + root.render( + React.createElement( + 'x-foo-component', + {'>': 'selected'}, + null, + ), + ); + }); + + if (i === 0) { + assertConsoleErrorDev([ + 'Invalid attribute name: `>`\n' + + ' in x-foo-component (at **)', + ]); + } + expect(container.firstChild.attributes.length).toBe(0); + } }); it('should reject attribute key injection attack on update for regular DOM', async () => { - await expect(async () => { - for (let i = 0; i < 3; i++) { - const container = document.createElement('div'); - const beforeUpdate = React.createElement('div', {}, null); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(beforeUpdate); - }); - await act(() => { - root.render( - React.createElement( - 'div', - {'blah" onclick="beevil" noise="hi': 'selected'}, - null, - ), - ); - }); - - expect(container.firstChild.attributes.length).toBe(0); - await act(() => { - root.render( - React.createElement( - 'div', - {'>
': 'selected'}, - null, - ), - ); - }); - - expect(container.firstChild.attributes.length).toBe(0); + for (let i = 0; i < 3; i++) { + const container = document.createElement('div'); + const beforeUpdate = React.createElement('div', {}, null); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(beforeUpdate); + }); + await act(() => { + root.render( + React.createElement( + 'div', + {'blah" onclick="beevil" noise="hi': 'selected'}, + null, + ), + ); + }); + + if (i === 0) { + assertConsoleErrorDev([ + 'Invalid attribute name: `blah" onclick="beevil" noise="hi`\n' + + ' in div (at **)', + ]); } - }).toErrorDev([ - 'Invalid attribute name: `blah" onclick="beevil" noise="hi`', - 'Invalid attribute name: `>
`', - ]); + expect(container.firstChild.attributes.length).toBe(0); + await act(() => { + root.render( + React.createElement( + 'div', + {'>
': 'selected'}, + null, + ), + ); + }); + if (i === 0) { + assertConsoleErrorDev([ + 'Invalid attribute name: `>
`\n' + + ' in div (at **)', + ]); + } + + expect(container.firstChild.attributes.length).toBe(0); + } }); it('should reject attribute key injection attack on update for custom elements', async () => { - await expect(async () => { - for (let i = 0; i < 3; i++) { - const container = document.createElement('div'); - const beforeUpdate = React.createElement('x-foo-component', {}, null); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(beforeUpdate); - }); - await act(() => { - root.render( - React.createElement( - 'x-foo-component', - {'blah" onclick="beevil" noise="hi': 'selected'}, - null, - ), - ); - }); - - expect(container.firstChild.attributes.length).toBe(0); - await act(() => { - root.render( - React.createElement( - 'x-foo-component', - {'>': 'selected'}, - null, - ), - ); - }); - - expect(container.firstChild.attributes.length).toBe(0); + for (let i = 0; i < 3; i++) { + const container = document.createElement('div'); + const beforeUpdate = React.createElement('x-foo-component', {}, null); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(beforeUpdate); + }); + await act(() => { + root.render( + React.createElement( + 'x-foo-component', + {'blah" onclick="beevil" noise="hi': 'selected'}, + null, + ), + ); + }); + + if (i === 0) { + assertConsoleErrorDev([ + 'Invalid attribute name: `blah" onclick="beevil" noise="hi`\n' + + ' in x-foo-component (at **)', + ]); } - }).toErrorDev([ - 'Invalid attribute name: `blah" onclick="beevil" noise="hi`', - 'Invalid attribute name: `>`', - ]); + expect(container.firstChild.attributes.length).toBe(0); + await act(() => { + root.render( + React.createElement( + 'x-foo-component', + {'>': 'selected'}, + null, + ), + ); + }); + + if (i === 0) { + assertConsoleErrorDev([ + 'Invalid attribute name: `>`\n' + + ' in x-foo-component (at **)', + ]); + } + expect(container.firstChild.attributes.length).toBe(0); + } }); it('should update arbitrary attributes for tags containing dashes', async () => { @@ -1382,36 +1417,38 @@ describe('ReactDOMComponent', () => { }); expect(nodeValueSetter).toHaveBeenCalledTimes(1); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'A component is changing a controlled input to be uncontrolled. This is likely caused by ' + 'the value changing from a defined to undefined, which should not happen. Decide between ' + - 'using a controlled or uncontrolled input element for the lifetime of the component.', - ); + 'using a controlled or uncontrolled input element for the lifetime of the component. ' + + 'More info: https://react.dev/link/controlled-components\n' + + ' in input (at **)', + ]); expect(nodeValueSetter).toHaveBeenCalledTimes(1); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'value` prop on `input` should not be null. Consider using an empty string to clear the ' + - 'component or `undefined` for uncontrolled components.', - ); + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ + '`value` prop on `input` should not be null. Consider using an empty string to clear the ' + + 'component or `undefined` for uncontrolled components.\n' + + ' in input (at **)', + ]); expect(nodeValueSetter).toHaveBeenCalledTimes(1); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( + await act(() => { + root.render(); + }); + assertConsoleErrorDev([ 'A component is changing an uncontrolled input to be controlled. This is likely caused by ' + 'the value changing from undefined to a defined value, which should not happen. Decide between ' + - 'using a controlled or uncontrolled input element for the lifetime of the component.', - ); + 'using a controlled or uncontrolled input element for the lifetime of the component. ' + + 'More info: https://react.dev/link/controlled-components\n' + + ' in input (at **)', + ]); expect(nodeValueSetter).toHaveBeenCalledTimes(2); await act(() => { @@ -1462,14 +1499,14 @@ describe('ReactDOMComponent', () => { it('should warn about non-string "is" attribute', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(