From 0d9834caeb3b334eaa1be45f136499f51303e7d3 Mon Sep 17 00:00:00 2001 From: michael faith Date: Sun, 16 Feb 2025 09:38:13 -0600 Subject: [PATCH 01/13] build: add support to the rollup build for building typescript packages (#32393) --- babel.config-ts.js | 15 + package.json | 5 +- .../__tests__/ReactTypeScriptClass-test.ts | 4 +- scripts/jest/config.base.js | 6 +- scripts/rollup/build.js | 45 +- scripts/rollup/bundles.js | 7 + scripts/rollup/packaging.js | 4 + scripts/rollup/wrappers.js | 36 ++ yarn.lock | 452 +++++++++++++----- 9 files changed, 441 insertions(+), 133 deletions(-) create mode 100644 babel.config-ts.js diff --git a/babel.config-ts.js b/babel.config-ts.js new file mode 100644 index 0000000000..20b35ec013 --- /dev/null +++ b/babel.config-ts.js @@ -0,0 +1,15 @@ +/** + * This file is purely being used for local jest runs, and doesn't participate in the build process. + */ +'use strict'; + +module.exports = { + plugins: [ + '@babel/plugin-syntax-jsx', + '@babel/plugin-transform-flow-strip-types', + ], + presets: [ + ['@babel/preset-env', {targets: {node: 'current'}}], + '@babel/preset-typescript', + ], +}; diff --git a/package.json b/package.json index cffd0ba28b..95fffa700a 100644 --- a/package.json +++ b/package.json @@ -35,11 +35,13 @@ "@babel/plugin-transform-template-literals": "^7.10.5", "@babel/preset-flow": "^7.10.4", "@babel/preset-react": "^7.23.3", + "@babel/preset-typescript": "^7.26.0", "@babel/traverse": "^7.11.0", "@rollup/plugin-babel": "^6.0.3", "@rollup/plugin-commonjs": "^24.0.1", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", + "@rollup/plugin-typescript": "^12.1.2", "abortcontroller-polyfill": "^1.7.5", "art": "0.10.1", "babel-plugin-syntax-trailing-function-commas": "^6.5.0", @@ -90,6 +92,7 @@ "react-lifecycles-compat": "^3.0.4", "rimraf": "^3.0.0", "rollup": "^3.29.5", + "rollup-plugin-dts": "^6.1.1", "rollup-plugin-prettier": "^4.1.1", "rollup-plugin-strip-banner": "^3.0.0", "semver": "^7.1.1", @@ -98,7 +101,7 @@ "targz": "^1.0.1", "through2": "^3.0.1", "tmp": "^0.1.0", - "typescript": "^3.7.5", + "typescript": "^5.4.3", "undici": "^5.28.4", "web-streams-polyfill": "^3.1.1", "yargs": "^15.3.1" diff --git a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts index 5f51cc6f38..603edb86ea 100644 --- a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts +++ b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts @@ -529,7 +529,7 @@ describe('ReactTypeScriptClass', function () { 'StateBasedOnContext uses the legacy contextTypes API which will soon be removed. ' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + (ReactFeatureFlags.enableOwnerStacks - ? ' in ProvideChildContextTypes.Object..ProvideChildContextTypes (at **)' + ? ' in ProvideChildContextTypes.createElement (at **)' : ' in StateBasedOnContext (at **)\n') + ' in ProvideChildContextTypes (at **)', ]); @@ -725,7 +725,7 @@ describe('ReactTypeScriptClass', function () { 'ReadContext uses the legacy contextTypes API which will soon be removed. ' + 'Use React.createContext() with static contextType instead. (https://react.dev/link/legacy-context)\n' + (ReactFeatureFlags.enableOwnerStacks - ? ' in ProvideContext.Object..ProvideContext (at **)' + ? ' in ProvideContext.createElement (at **)' : ' in ReadContext (at **)\n') + ' in ProvideContext (at **)', ]); diff --git a/scripts/jest/config.base.js b/scripts/jest/config.base.js index 6fa4a36194..262c6ab18a 100644 --- a/scripts/jest/config.base.js +++ b/scripts/jest/config.base.js @@ -7,7 +7,11 @@ module.exports = { '/scripts/bench/', ], transform: { - '.*': require.resolve('./preprocessor.js'), + '^.+\\.ts$': [ + 'babel-jest', + {configFile: require.resolve('../../babel.config-ts.js')}, + ], + '.(?!ts$)': require.resolve('./preprocessor.js'), }, prettierPath: require.resolve('prettier-2'), setupFiles: [require.resolve('./setupEnvironment.js')], diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index 547362dae7..53b308d16a 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -4,8 +4,10 @@ const rollup = require('rollup'); const babel = require('@rollup/plugin-babel').babel; const closure = require('./plugins/closure-plugin'); const flowRemoveTypes = require('flow-remove-types'); +const {dts} = require('rollup-plugin-dts'); const prettier = require('rollup-plugin-prettier'); const replace = require('@rollup/plugin-replace'); +const typescript = require('@rollup/plugin-typescript'); const stripBanner = require('rollup-plugin-strip-banner'); const chalk = require('chalk'); const resolve = require('@rollup/plugin-node-resolve').nodeResolve; @@ -61,6 +63,8 @@ const { RN_FB_PROD, RN_FB_PROFILING, BROWSER_SCRIPT, + CJS_DTS, + ESM_DTS, } = Bundles.bundleTypes; const {getFilename} = Bundles; @@ -250,9 +254,11 @@ function getFormat(bundleType) { case RN_FB_DEV: case RN_FB_PROD: case RN_FB_PROFILING: + case CJS_DTS: return `cjs`; case ESM_DEV: case ESM_PROD: + case ESM_DTS: return `es`; case BROWSER_SCRIPT: return `iife`; @@ -281,6 +287,8 @@ function isProductionBundleType(bundleType) { case RN_FB_PROD: case RN_FB_PROFILING: case BROWSER_SCRIPT: + case CJS_DTS: + case ESM_DTS: return true; default: throw new Error(`Unknown type: ${bundleType}`); @@ -303,6 +311,8 @@ function isProfilingBundleType(bundleType) { case ESM_DEV: case ESM_PROD: case BROWSER_SCRIPT: + case CJS_DTS: + case ESM_DTS: return false; case FB_WWW_PROFILING: case NODE_PROFILING: @@ -368,27 +378,36 @@ function getPlugins( pureExternalModules, bundle ) { + // Short-circuit if we're only building a .d.ts bundle + if (bundleType === CJS_DTS || bundleType === ESM_DTS) { + return [dts({tsconfig: bundle.tsconfig})]; + } try { const forks = Modules.getForks(bundleType, entry, moduleType, bundle); const isProduction = isProductionBundleType(bundleType); const isProfiling = isProfilingBundleType(bundleType); const needsMinifiedByClosure = - bundleType !== ESM_PROD && bundleType !== ESM_DEV; + bundleType !== ESM_PROD && + bundleType !== ESM_DEV && + // TODO(@poteto) figure out ICE in closure compiler for eslint-plugin-react-hooks (ts) + bundle.tsconfig == null; return [ // Keep dynamic imports as externals dynamicImports(), - { - name: 'rollup-plugin-flow-remove-types', - transform(code) { - const transformed = flowRemoveTypes(code); - return { - code: transformed.toString(), - map: null, - }; - }, - }, + bundle.tsconfig != null + ? typescript({tsconfig: bundle.tsconfig}) + : { + name: 'rollup-plugin-flow-remove-types', + transform(code) { + const transformed = flowRemoveTypes(code); + return { + code: transformed.toString(), + map: null, + }; + }, + }, // Shim any modules that need forking in this environment. useForks(forks), // Ensure we don't try to bundle any fbjs modules. @@ -839,7 +858,9 @@ async function buildEverything() { [bundle, RN_FB_DEV], [bundle, RN_FB_PROD], [bundle, RN_FB_PROFILING], - [bundle, BROWSER_SCRIPT] + [bundle, BROWSER_SCRIPT], + [bundle, CJS_DTS], + [bundle, ESM_DTS] ); } diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 04bfb1a0e5..c66cff82c5 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -26,6 +26,8 @@ const bundleTypes = { RN_FB_PROD: 'RN_FB_PROD', RN_FB_PROFILING: 'RN_FB_PROFILING', BROWSER_SCRIPT: 'BROWSER_SCRIPT', + CJS_DTS: 'CJS_DTS', + ESM_DTS: 'ESM_DTS', }; const { @@ -47,6 +49,8 @@ const { RN_FB_PROD, RN_FB_PROFILING, BROWSER_SCRIPT, + CJS_DTS, + ESM_DTS, } = bundleTypes; const moduleTypes = { @@ -1270,6 +1274,9 @@ function getFilename(bundle, bundleType) { return `${globalName}-profiling.js`; case BROWSER_SCRIPT: return `${name}.js`; + case CJS_DTS: + case ESM_DTS: + return `${name}.d.ts`; } } diff --git a/scripts/rollup/packaging.js b/scripts/rollup/packaging.js index bc83cb8789..564c40f71b 100644 --- a/scripts/rollup/packaging.js +++ b/scripts/rollup/packaging.js @@ -34,6 +34,8 @@ const { RN_FB_PROD, RN_FB_PROFILING, BROWSER_SCRIPT, + CJS_DTS, + ESM_DTS, } = Bundles.bundleTypes; function getPackageName(name) { @@ -49,6 +51,7 @@ function getBundleOutputPath(bundle, bundleType, filename, packageName) { return `build/node_modules/${packageName}/cjs/${filename}`; case ESM_DEV: case ESM_PROD: + case ESM_DTS: return `build/node_modules/${packageName}/esm/${filename}`; case BUN_DEV: case BUN_PROD: @@ -56,6 +59,7 @@ function getBundleOutputPath(bundle, bundleType, filename, packageName) { case NODE_DEV: case NODE_PROD: case NODE_PROFILING: + case CJS_DTS: return `build/node_modules/${packageName}/cjs/${filename}`; case FB_WWW_DEV: case FB_WWW_PROD: diff --git a/scripts/rollup/wrappers.js b/scripts/rollup/wrappers.js index e01ca30a6d..1773253cc9 100644 --- a/scripts/rollup/wrappers.js +++ b/scripts/rollup/wrappers.js @@ -21,6 +21,8 @@ const { RN_FB_PROD, RN_FB_PROFILING, BROWSER_SCRIPT, + CJS_DTS, + ESM_DTS, } = bundleTypes; const {RECONCILER} = moduleTypes; @@ -248,6 +250,16 @@ ${source} Object.defineProperty(module.exports, "__esModule", { value: true }); `; }, + + /***************** CJS_DTS *****************/ + [CJS_DTS](source, globalName, filename, moduleType) { + return source; + }, + + /***************** ESM_DTS *****************/ + [ESM_DTS](source, globalName, filename, moduleType) { + return source; + }, }; const licenseHeaderWrappers = { @@ -464,6 +476,30 @@ ${license} * @preventMunge */ +${source}`; + }, + + /***************** CJS_DTS *****************/ + [CJS_DTS](source, globalName, filename, moduleType) { + return `/** + * @license React + * ${filename} + * +${license} + */ + +${source}`; + }, + + /***************** ESM_DTS *****************/ + [ESM_DTS](source, globalName, filename, moduleType) { + return `/** + * @license React + * ${filename} + * +${license} + */ + ${source}`; }, }; diff --git a/yarn.lock b/yarn.lock index 4922028daf..44d5906251 100644 --- a/yarn.lock +++ b/yarn.lock @@ -68,6 +68,15 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" +"@babel/code-frame@^7.26.2": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@babel/code-frame@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" @@ -225,6 +234,17 @@ "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" +"@babel/generator@^7.26.9": + version "7.26.9" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.9.tgz#75a9482ad3d0cc7188a537aa4910bc59db67cbca" + integrity sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg== + dependencies: + "@babel/parser" "^7.26.9" + "@babel/types" "^7.26.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + "@babel/generator@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03" @@ -263,6 +283,13 @@ dependencies: "@babel/types" "^7.22.5" +"@babel/helper-annotate-as-pure@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz#d8eac4d2dc0d7b6e11fa6e535332e0d3184f06b4" + integrity sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g== + dependencies: + "@babel/types" "^7.25.9" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" @@ -369,6 +396,19 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" "@babel/helper-split-export-declaration" "^7.18.6" +"@babel/helper-create-class-features-plugin@^7.25.9": + version "7.26.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz#d6f83e3039547fbb39967e78043cd3c8b7820c71" + integrity sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-member-expression-to-functions" "^7.25.9" + "@babel/helper-optimise-call-expression" "^7.25.9" + "@babel/helper-replace-supers" "^7.26.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + "@babel/traverse" "^7.26.9" + semver "^6.3.1" + "@babel/helper-create-regexp-features-plugin@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" @@ -506,6 +546,14 @@ dependencies: "@babel/types" "^7.20.7" +"@babel/helper-member-expression-to-functions@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz#9dfffe46f727005a5ea29051ac835fb735e4c1a3" + integrity sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + "@babel/helper-module-imports@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" @@ -534,6 +582,14 @@ dependencies: "@babel/types" "^7.22.15" +"@babel/helper-module-imports@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + "@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" @@ -572,6 +628,15 @@ "@babel/helper-split-export-declaration" "^7.24.5" "@babel/helper-validator-identifier" "^7.24.5" +"@babel/helper-module-transforms@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" + integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/helper-optimise-call-expression@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" @@ -593,6 +658,13 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-optimise-call-expression@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz#3324ae50bae7e2ab3c33f60c9a877b6a0146b54e" + integrity sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ== + dependencies: + "@babel/types" "^7.25.9" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz#a924607dd254a65695e5bd209b98b902b3b2f11a" @@ -608,6 +680,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== +"@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35" + integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg== + "@babel/helper-plugin-utils@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" @@ -663,6 +740,15 @@ "@babel/traverse" "^7.20.7" "@babel/types" "^7.20.7" +"@babel/helper-replace-supers@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz#6cb04e82ae291dae8e72335dfe438b0725f14c8d" + integrity sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.25.9" + "@babel/helper-optimise-call-expression" "^7.25.9" + "@babel/traverse" "^7.26.5" + "@babel/helper-simple-access@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" @@ -706,6 +792,14 @@ dependencies: "@babel/types" "^7.20.0" +"@babel/helper-skip-transparent-expression-wrappers@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz#0b2e1b62d560d6b1954893fd2b705dc17c91f0c9" + integrity sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + "@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" @@ -744,6 +838,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + "@babel/helper-validator-identifier@^7.10.4": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" @@ -769,6 +868,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + "@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" @@ -779,6 +883,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== +"@babel/helper-validator-option@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" + integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== + "@babel/helper-wrap-function@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" @@ -905,6 +1014,13 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== +"@babel/parser@^7.26.9": + version "7.26.9" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.9.tgz#d9e78bee6dc80f9efd8f2349dcfbbcdace280fd5" + integrity sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A== + dependencies: + "@babel/types" "^7.26.9" + "@babel/plugin-external-helpers@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.10.4.tgz#40d38e8e48a1fa3766ab43496253266ca26783ce" @@ -1197,6 +1313,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" +"@babel/plugin-syntax-jsx@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz#a34313a178ea56f1951599b929c1ceacee719290" + integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/plugin-syntax-jsx@^7.7.2": version "7.24.1" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" @@ -1281,6 +1404,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/plugin-syntax-typescript@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz#67dda2b74da43727cf21d46cf9afef23f4365399" + integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/plugin-syntax-typescript@^7.7.2": version "7.24.1" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" @@ -1533,6 +1663,14 @@ "@babel/helper-simple-access" "^7.16.0" babel-plugin-dynamic-import-node "^2.3.3" +"@babel/plugin-transform-modules-commonjs@^7.25.9": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz#8f011d44b20d02c3de44d8850d971d8497f981fb" + integrity sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ== + dependencies: + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/plugin-transform-modules-systemjs@^7.10.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz#6270099c854066681bae9e05f87e1b9cadbe8c85" @@ -1794,6 +1932,17 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript" "^7.16.0" +"@babel/plugin-transform-typescript@^7.25.9": + version "7.26.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz#2e9caa870aa102f50d7125240d9dbf91334b0950" + integrity sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-create-class-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.26.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + "@babel/plugin-syntax-typescript" "^7.25.9" + "@babel/plugin-transform-unicode-escapes@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007" @@ -1936,6 +2085,17 @@ "@babel/helper-validator-option" "^7.14.5" "@babel/plugin-transform-typescript" "^7.16.0" +"@babel/preset-typescript@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz#4a570f1b8d104a242d923957ffa1eaff142a106d" + integrity sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-validator-option" "^7.25.9" + "@babel/plugin-syntax-jsx" "^7.25.9" + "@babel/plugin-transform-modules-commonjs" "^7.25.9" + "@babel/plugin-transform-typescript" "^7.25.9" + "@babel/register@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.14.5.tgz#d0eac615065d9c2f1995842f85d6e56c345f3233" @@ -1995,6 +2155,15 @@ "@babel/parser" "^7.24.0" "@babel/types" "^7.24.0" +"@babel/template@^7.26.9": + version "7.26.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.26.9.tgz#4577ad3ddf43d194528cff4e1fa6b232fa609bb2" + integrity sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/parser" "^7.26.9" + "@babel/types" "^7.26.9" + "@babel/template@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" @@ -2096,6 +2265,19 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.9": + version "7.26.9" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.9.tgz#4398f2394ba66d05d988b2ad13c219a2c857461a" + integrity sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.9" + "@babel/parser" "^7.26.9" + "@babel/template" "^7.26.9" + "@babel/types" "^7.26.9" + debug "^4.3.1" + globals "^11.1.0" + "@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.7", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.3.3": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.5.tgz#7661930afc638a5383eb0c4aee59b74f38db84d7" @@ -2148,6 +2330,14 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@babel/types@^7.25.9", "@babel/types@^7.26.9": + version "7.26.9" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.9.tgz#08b43dec79ee8e682c2ac631c010bdcac54a21ce" + integrity sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/types@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" @@ -2785,6 +2975,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== +"@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.9": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" @@ -3175,6 +3370,14 @@ "@rollup/pluginutils" "^5.0.1" magic-string "^0.27.0" +"@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.2" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33" @@ -3184,100 +3387,109 @@ estree-walker "^2.0.2" picomatch "^2.3.1" -"@rollup/rollup-android-arm-eabi@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.1.tgz#c18bad635ba24220a6c8cc427ab2cab12e1531a3" - integrity sha512-/pqA4DmqyCm8u5YIDzIdlLcEmuvxb0v8fZdFhVMszSpDTgbQKdw3/mB3eMUHIbubtJ6F9j+LtmyCnHTEqIHyzA== +"@rollup/pluginutils@^5.1.0": + version "5.1.4" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz#bb94f1f9eaaac944da237767cdfee6c5b2262d4a" + integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^4.0.2" -"@rollup/rollup-android-arm64@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.1.tgz#b5c00344b80f20889b72bfe65d3c209cef247362" - integrity sha512-If3PDskT77q7zgqVqYuj7WG3WC08G1kwXGVFi9Jr8nY6eHucREHkfpX79c0ACAjLj3QIWKPJR7w4i+f5EdLH5Q== +"@rollup/rollup-android-arm-eabi@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.7.tgz#e554185b1afa5509a7a4040d15ec0c3b4435ded1" + integrity sha512-l6CtzHYo8D2TQ3J7qJNpp3Q1Iye56ssIAtqbM2H8axxCEEwvN7o8Ze9PuIapbxFL3OHrJU2JBX6FIIVnP/rYyw== -"@rollup/rollup-darwin-arm64@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.1.tgz#78e5358d4a2a08c090f75dd87fa2eada42eca1e5" - integrity sha512-zCpKHioQ9KgZToFp5Wvz6zaWbMzYQ2LJHQ+QixDKq52KKrF65ueu6Af4hLlLWHjX1Wf/0G5kSJM9PySW9IrvHA== +"@rollup/rollup-android-arm64@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.7.tgz#b1ee64bb413b2feba39803b0a1bebf2a9f3d70e1" + integrity sha512-KvyJpFUueUnSp53zhAa293QBYqwm94TgYTIfXyOTtidhm5V0LbLCJQRGkQClYiX3FXDQGSvPxOTD/6rPStMMDg== -"@rollup/rollup-darwin-x64@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.1.tgz#c04c9e173244d44de50278f3f893fb68d987fcc6" - integrity sha512-sFvF+t2+TyUo/ZQqUcifrJIgznx58oFZbdHS9TvHq3xhPVL9nOp+yZ6LKrO9GWTP+6DbFtoyLDbjTpR62Mbr3Q== +"@rollup/rollup-darwin-arm64@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.7.tgz#bfdce3e07a345dd1bd628f3b796050f39629d7f0" + integrity sha512-jq87CjmgL9YIKvs8ybtIC98s/M3HdbqXhllcy9EdLV0yMg1DpxES2gr65nNy7ObNo/vZ/MrOTxt0bE5LinL6mA== -"@rollup/rollup-freebsd-arm64@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.1.tgz#3bdf18d4ef32dcfe9b20bba18d7a53a101ed79d9" - integrity sha512-NbOa+7InvMWRcY9RG+B6kKIMD/FsnQPH0MWUvDlQB1iXnF/UcKSudCXZtv4lW+C276g3w5AxPbfry5rSYvyeYA== +"@rollup/rollup-darwin-x64@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.7.tgz#781a94a537c57bdf0a500e47a25ab5985e5e8dff" + integrity sha512-rSI/m8OxBjsdnMMg0WEetu/w+LhLAcCDEiL66lmMX4R3oaml3eXz3Dxfvrxs1FbzPbJMaItQiksyMfv1hoIxnA== -"@rollup/rollup-freebsd-x64@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.1.tgz#35867b15c276f4b4ca8eb226f7dd6df8c64640db" - integrity sha512-JRBRmwvHPXR881j2xjry8HZ86wIPK2CcDw0EXchE1UgU0ubWp9nvlT7cZYKc6bkypBt745b4bglf3+xJ7hXWWw== +"@rollup/rollup-freebsd-arm64@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.7.tgz#7a028357cbd12c5869c446ad18177c89f3405102" + integrity sha512-oIoJRy3ZrdsXpFuWDtzsOOa/E/RbRWXVokpVrNnkS7npz8GEG++E1gYbzhYxhxHbO2om1T26BZjVmdIoyN2WtA== -"@rollup/rollup-linux-arm-gnueabihf@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.1.tgz#92c212d1b38c105bd1eb101254722d27d869b1ac" - integrity sha512-PKvszb+9o/vVdUzCCjL0sKHukEQV39tD3fepXxYrHE3sTKrRdCydI7uldRLbjLmDA3TFDmh418XH19NOsDRH8g== +"@rollup/rollup-freebsd-x64@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.7.tgz#f24836a6371cccc4408db74f0fd986dacf098950" + integrity sha512-X++QSLm4NZfZ3VXGVwyHdRf58IBbCu9ammgJxuWZYLX0du6kZvdNqPwrjvDfwmi6wFdvfZ/s6K7ia0E5kI7m8Q== -"@rollup/rollup-linux-arm-musleabihf@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.1.tgz#ebb94d8cd438f23e38caa4a87ca80d4cf5b50fa1" - integrity sha512-9WHEMV6Y89eL606ReYowXuGF1Yb2vwfKWKdD1A5h+OYnPZSJvxbEjxTRKPgi7tkP2DSnW0YLab1ooy+i/FQp/Q== +"@rollup/rollup-linux-arm-gnueabihf@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.7.tgz#95f27e96f0eb9b9ae9887739a8b6dffc90c1237f" + integrity sha512-Z0TzhrsNqukTz3ISzrvyshQpFnFRfLunYiXxlCRvcrb3nvC5rVKI+ZXPFG/Aa4jhQa1gHgH3A0exHaRRN4VmdQ== -"@rollup/rollup-linux-arm64-gnu@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.1.tgz#ce6a5eacbd5fd4bdf7bf27bd818980230bdb9fab" - integrity sha512-tZWc9iEt5fGJ1CL2LRPw8OttkCBDs+D8D3oEM8mH8S1ICZCtFJhD7DZ3XMGM8kpqHvhGUTvNUYVDnmkj4BDXnw== +"@rollup/rollup-linux-arm-musleabihf@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.7.tgz#677b34fba9d070877736c3fe8b02aacb5e142d97" + integrity sha512-nkznpyXekFAbvFBKBy4nNppSgneB1wwG1yx/hujN3wRnhnkrYVugMTCBXED4+Ni6thoWfQuHNYbFjgGH0MBXtw== -"@rollup/rollup-linux-arm64-musl@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.1.tgz#31b4e0a543607e6eb4f982ffb45830919a952a83" - integrity sha512-FTYc2YoTWUsBz5GTTgGkRYYJ5NGJIi/rCY4oK/I8aKowx1ToXeoVVbIE4LGAjsauvlhjfl0MYacxClLld1VrOw== +"@rollup/rollup-linux-arm64-gnu@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.7.tgz#32d3d19dedde54e91574a098f22ea43a09cf63dd" + integrity sha512-KCjlUkcKs6PjOcxolqrXglBDcfCuUCTVlX5BgzgoJHw+1rWH1MCkETLkLe5iLLS9dP5gKC7mp3y6x8c1oGBUtA== -"@rollup/rollup-linux-loongarch64-gnu@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.1.tgz#ad7b35f193f1d2e0dc37eba733069b4af5f6498d" - integrity sha512-F51qLdOtpS6P1zJVRzYM0v6MrBNypyPEN1GfMiz0gPu9jN8ScGaEFIZQwteSsGKg799oR5EaP7+B2jHgL+d+Kw== +"@rollup/rollup-linux-arm64-musl@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.7.tgz#a58dff44a18696df65ed8c0ad68a2945cf900484" + integrity sha512-uFLJFz6+utmpbR313TTx+NpPuAXbPz4BhTQzgaP0tozlLnGnQ6rCo6tLwaSa6b7l6gRErjLicXQ1iPiXzYotjw== -"@rollup/rollup-linux-powerpc64le-gnu@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.1.tgz#b713a55d7eac4d2c8a0109c3daca6ea85fc178b3" - integrity sha512-wO0WkfSppfX4YFm5KhdCCpnpGbtgQNj/tgvYzrVYFKDpven8w2N6Gg5nB6w+wAMO3AIfSTWeTjfVe+uZ23zAlg== +"@rollup/rollup-linux-loongarch64-gnu@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.7.tgz#a7488ab078233111e8aeb370d1ecf107ec7e1716" + integrity sha512-ws8pc68UcJJqCpneDFepnwlsMUFoWvPbWXT/XUrJ7rWUL9vLoIN3GAasgG+nCvq8xrE3pIrd+qLX/jotcLy0Qw== -"@rollup/rollup-linux-riscv64-gnu@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.1.tgz#bea4fd8ad190e9bc1d11efafa2efc9d121f50b96" - integrity sha512-iWswS9cIXfJO1MFYtI/4jjlrGb/V58oMu4dYJIKnR5UIwbkzR0PJ09O0PDZT0oJ3LYWXBSWahNf/Mjo6i1E5/g== +"@rollup/rollup-linux-powerpc64le-gnu@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.7.tgz#e9b9c0d6bd248a92b2d6ec01ebf99c62ae1f2e9a" + integrity sha512-vrDk9JDa/BFkxcS2PbWpr0C/LiiSLxFbNOBgfbW6P8TBe9PPHx9Wqbvx2xgNi1TOAyQHQJ7RZFqBiEohm79r0w== -"@rollup/rollup-linux-s390x-gnu@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.1.tgz#cc98c32733ca472635759c78a79b5f8d887b2a6a" - integrity sha512-RKt8NI9tebzmEthMnfVgG3i/XeECkMPS+ibVZjZ6mNekpbbUmkNWuIN2yHsb/mBPyZke4nlI4YqIdFPgKuoyQQ== +"@rollup/rollup-linux-riscv64-gnu@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.7.tgz#0df84ce2bea48ee686fb55060d76ab47aff45c4c" + integrity sha512-rB+ejFyjtmSo+g/a4eovDD1lHWHVqizN8P0Hm0RElkINpS0XOdpaXloqM4FBkF9ZWEzg6bezymbpLmeMldfLTw== -"@rollup/rollup-linux-x64-gnu@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.1.tgz#5c009c264a7ce0e19b40890ca9945440bb420691" - integrity sha512-WQFLZ9c42ECqEjwg/GHHsouij3pzLXkFdz0UxHa/0OM12LzvX7DzedlY0SIEly2v18YZLRhCRoHZDxbBSWoGYg== +"@rollup/rollup-linux-s390x-gnu@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.7.tgz#73df374c57d036856e33dbd2715138922e91e452" + integrity sha512-nNXNjo4As6dNqRn7OrsnHzwTgtypfRA3u3AKr0B3sOOo+HkedIbn8ZtFnB+4XyKJojIfqDKmbIzO1QydQ8c+Pw== -"@rollup/rollup-linux-x64-musl@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.1.tgz#73d2f44070c23e031262b601927fdb4eec253bc1" - integrity sha512-BLoiyHDOWoS3uccNSADMza6V6vCNiphi94tQlVIL5de+r6r/CCQuNnerf+1g2mnk2b6edp5dk0nhdZ7aEjOBsA== +"@rollup/rollup-linux-x64-gnu@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.7.tgz#f27af0b55f0cdd84e182e6cd44a6d03da0458149" + integrity sha512-9kPVf9ahnpOMSGlCxXGv980wXD0zRR3wyk8+33/MXQIpQEOpaNe7dEHm5LMfyRZRNt9lMEQuH0jUKj15MkM7QA== -"@rollup/rollup-win32-arm64-msvc@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.1.tgz#fa106304818078f9d3fc9005642ad99f596eed2d" - integrity sha512-w2l3UnlgYTNNU+Z6wOR8YdaioqfEnwPjIsJ66KxKAf0p+AuL2FHeTX6qvM+p/Ue3XPBVNyVSfCrfZiQh7vZHLQ== +"@rollup/rollup-linux-x64-musl@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.7.tgz#c7981ad5cfb8c3cd5d643d33ca54e4d2802b9201" + integrity sha512-7wJPXRWTTPtTFDFezA8sle/1sdgxDjuMoRXEKtx97ViRxGGkVQYovem+Q8Pr/2HxiHp74SSRG+o6R0Yq0shPwQ== -"@rollup/rollup-win32-ia32-msvc@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.1.tgz#a1a394c705a0d2a974a124c4b471fc1cf851a56f" - integrity sha512-Am9H+TGLomPGkBnaPWie4F3x+yQ2rr4Bk2jpwy+iV+Gel9jLAu/KqT8k3X4jxFPW6Zf8OMnehyutsd+eHoq1WQ== +"@rollup/rollup-win32-arm64-msvc@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.7.tgz#06cedc0ef3cbf1cbd8abcf587090712e40ae6941" + integrity sha512-MN7aaBC7mAjsiMEZcsJvwNsQVNZShgES/9SzWp1HC9Yjqb5OpexYnRjF7RmE4itbeesHMYYQiAtUAQaSKs2Rfw== -"@rollup/rollup-win32-x64-msvc@4.32.1": - version "4.32.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.1.tgz#512db088df67afee8f07183cdf8c9eecd64f6ef8" - integrity sha512-ar80GhdZb4DgmW3myIS9nRFYcpJRSME8iqWgzH2i44u+IdrzmiXVxeFnExQ5v4JYUSpg94bWjevMG8JHf1Da5Q== +"@rollup/rollup-win32-ia32-msvc@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.7.tgz#90b39b977b14961a769be6ea61238e7fc668dd4d" + integrity sha512-aeawEKYswsFu1LhDM9RIgToobquzdtSc4jSVqHV8uApz4FVvhFl/mKh92wc8WpFc6aYCothV/03UjY6y7yLgbg== + +"@rollup/rollup-win32-x64-msvc@4.34.7": + version "4.34.7" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.7.tgz#6531d61e7141091eaab0461ee8e0380c10e4ca57" + integrity sha512-4ZedScpxxIrVO7otcZ8kCX1mZArtH2Wfj3uFCxRJ9NO80gg1XV0U/b2f/MKaGwj2X3QopHfoWiDQ917FRpwY3w== "@sinclair/typebox@^0.25.16": version "0.25.24" @@ -3468,21 +3680,11 @@ dependencies: "@types/estree" "*" -"@types/estree@*": - version "0.0.42" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.42.tgz#8d0c1f480339efedb3e46070e22dd63e0430dd11" - integrity sha512-K1DPVvnBCPxzD+G51/cxVIoc2X8uUVl1zpJeE6iKcgHMj4+tbat5Xu4TjV7v2QSDbIeAfLi2hIk+u2+s0MlpUQ== - -"@types/estree@1.0.6", "@types/estree@^1.0.6": +"@types/estree@*", "@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.6": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== -"@types/estree@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" - integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== - "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": version "4.17.35" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f" @@ -11370,6 +11572,11 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + 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" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -11976,6 +12183,13 @@ magic-string@^0.27.0: dependencies: "@jridgewell/sourcemap-codec" "^1.4.13" +magic-string@^0.30.10: + version "0.30.17" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + make-dir@^1.0.0, make-dir@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" @@ -14343,9 +14557,9 @@ readdirp@^2.2.1: readable-stream "^2.0.2" readdirp@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.1.tgz#bd115327129672dc47f87408f05df9bd9ca3ef55" - integrity sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw== + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== readdirp@~3.6.0: version "3.6.0" @@ -14744,6 +14958,15 @@ roarr@^2.15.3: semver-compare "^1.0.0" sprintf-js "^1.1.2" +rollup-plugin-dts@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/rollup-plugin-dts/-/rollup-plugin-dts-6.1.1.tgz#46b33f4d1d7f4e66f1171ced9b282ac11a15a254" + integrity sha512-aSHRcJ6KG2IHIioYlvAOcEq6U99sVtqDDKVhnwt70rW6tsz3tv5OSjEiWcgzfsHdLyGXZ/3b/7b/+Za3Y6r1XA== + dependencies: + magic-string "^0.30.10" + optionalDependencies: + "@babel/code-frame" "^7.24.2" + 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" @@ -14781,31 +15004,31 @@ rollup@^3.29.5: fsevents "~2.3.2" rollup@^4.24.0: - version "4.32.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.32.1.tgz#95309604d92c3d21cbf06c3ee46a098209ce13a4" - integrity sha512-z+aeEsOeEa3mEbS1Tjl6sAZ8NE3+AalQz1RJGj81M+fizusbdDMoEJwdJNHfaB40Scr4qNu+welOfes7maKonA== + version "4.34.7" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.34.7.tgz#e00d8550688a616a3481c6446bb688d4c753ba8f" + integrity sha512-8qhyN0oZ4x0H6wmBgfKxJtxM7qS98YJ0k0kNh5ECVtuchIJ7z9IVVvzpmtQyT10PXKMtBxYr1wQ5Apg8RS8kXQ== dependencies: "@types/estree" "1.0.6" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.32.1" - "@rollup/rollup-android-arm64" "4.32.1" - "@rollup/rollup-darwin-arm64" "4.32.1" - "@rollup/rollup-darwin-x64" "4.32.1" - "@rollup/rollup-freebsd-arm64" "4.32.1" - "@rollup/rollup-freebsd-x64" "4.32.1" - "@rollup/rollup-linux-arm-gnueabihf" "4.32.1" - "@rollup/rollup-linux-arm-musleabihf" "4.32.1" - "@rollup/rollup-linux-arm64-gnu" "4.32.1" - "@rollup/rollup-linux-arm64-musl" "4.32.1" - "@rollup/rollup-linux-loongarch64-gnu" "4.32.1" - "@rollup/rollup-linux-powerpc64le-gnu" "4.32.1" - "@rollup/rollup-linux-riscv64-gnu" "4.32.1" - "@rollup/rollup-linux-s390x-gnu" "4.32.1" - "@rollup/rollup-linux-x64-gnu" "4.32.1" - "@rollup/rollup-linux-x64-musl" "4.32.1" - "@rollup/rollup-win32-arm64-msvc" "4.32.1" - "@rollup/rollup-win32-ia32-msvc" "4.32.1" - "@rollup/rollup-win32-x64-msvc" "4.32.1" + "@rollup/rollup-android-arm-eabi" "4.34.7" + "@rollup/rollup-android-arm64" "4.34.7" + "@rollup/rollup-darwin-arm64" "4.34.7" + "@rollup/rollup-darwin-x64" "4.34.7" + "@rollup/rollup-freebsd-arm64" "4.34.7" + "@rollup/rollup-freebsd-x64" "4.34.7" + "@rollup/rollup-linux-arm-gnueabihf" "4.34.7" + "@rollup/rollup-linux-arm-musleabihf" "4.34.7" + "@rollup/rollup-linux-arm64-gnu" "4.34.7" + "@rollup/rollup-linux-arm64-musl" "4.34.7" + "@rollup/rollup-linux-loongarch64-gnu" "4.34.7" + "@rollup/rollup-linux-powerpc64le-gnu" "4.34.7" + "@rollup/rollup-linux-riscv64-gnu" "4.34.7" + "@rollup/rollup-linux-s390x-gnu" "4.34.7" + "@rollup/rollup-linux-x64-gnu" "4.34.7" + "@rollup/rollup-linux-x64-musl" "4.34.7" + "@rollup/rollup-win32-arm64-msvc" "4.34.7" + "@rollup/rollup-win32-ia32-msvc" "4.34.7" + "@rollup/rollup-win32-x64-msvc" "4.34.7" fsevents "~2.3.2" rrweb-cssom@^0.6.0: @@ -16530,11 +16753,6 @@ typescript@3.9.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.3.tgz#d3ac8883a97c26139e42df5e93eeece33d610b8a" integrity sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ== -typescript@^3.7.5: - version "3.7.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" - integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== - typescript@^5.4.3: version "5.7.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e" From 037b25cfdcd18deea0e1c6c2e8d2548dbf32f7f3 Mon Sep 17 00:00:00 2001 From: michael faith Date: Sun, 16 Feb 2025 12:23:44 -0600 Subject: [PATCH 02/13] test(eslint): create eslint test fixtures (#32396) --- fixtures/{eslint => eslint-v6}/.eslintrc.json | 7 +- fixtures/eslint-v6/README.md | 12 + fixtures/eslint-v6/build.mjs | 5 + fixtures/eslint-v6/index.js | 143 +++ fixtures/eslint-v6/package.json | 12 + fixtures/eslint-v6/yarn.lock | 865 ++++++++++++++++++ fixtures/eslint-v7/.eslintrc.json | 14 + fixtures/eslint-v7/README.md | 12 + fixtures/eslint-v7/build.mjs | 5 + fixtures/eslint-v7/index.js | 143 +++ fixtures/eslint-v7/package.json | 12 + fixtures/eslint-v7/yarn.lock | 769 ++++++++++++++++ fixtures/eslint-v8/.eslintrc.json | 14 + fixtures/eslint-v8/README.md | 12 + fixtures/eslint-v8/build.mjs | 5 + fixtures/eslint-v8/index.js | 143 +++ fixtures/eslint-v8/package.json | 12 + fixtures/eslint-v8/yarn.lock | 676 ++++++++++++++ fixtures/eslint-v9/README.md | 12 + fixtures/eslint-v9/build.mjs | 5 + fixtures/eslint-v9/eslint.config.mjs | 21 + fixtures/eslint-v9/index.js | 143 +++ fixtures/eslint-v9/package.json | 12 + fixtures/eslint-v9/yarn.lock | 579 ++++++++++++ fixtures/eslint/README.md | 7 - fixtures/eslint/index.js | 26 - fixtures/eslint/package.json | 12 - fixtures/eslint/proxy/index.js | 35 - fixtures/eslint/proxy/package.json | 4 - fixtures/eslint/watch.sh | 3 - fixtures/eslint/yarn.lock | 853 ----------------- 31 files changed, 3629 insertions(+), 944 deletions(-) rename fixtures/{eslint => eslint-v6}/.eslintrc.json (52%) create mode 100644 fixtures/eslint-v6/README.md create mode 100644 fixtures/eslint-v6/build.mjs create mode 100644 fixtures/eslint-v6/index.js create mode 100644 fixtures/eslint-v6/package.json create mode 100644 fixtures/eslint-v6/yarn.lock create mode 100644 fixtures/eslint-v7/.eslintrc.json create mode 100644 fixtures/eslint-v7/README.md create mode 100644 fixtures/eslint-v7/build.mjs create mode 100644 fixtures/eslint-v7/index.js create mode 100644 fixtures/eslint-v7/package.json create mode 100644 fixtures/eslint-v7/yarn.lock create mode 100644 fixtures/eslint-v8/.eslintrc.json create mode 100644 fixtures/eslint-v8/README.md create mode 100644 fixtures/eslint-v8/build.mjs create mode 100644 fixtures/eslint-v8/index.js create mode 100644 fixtures/eslint-v8/package.json create mode 100644 fixtures/eslint-v8/yarn.lock create mode 100644 fixtures/eslint-v9/README.md create mode 100644 fixtures/eslint-v9/build.mjs create mode 100644 fixtures/eslint-v9/eslint.config.mjs create mode 100644 fixtures/eslint-v9/index.js create mode 100644 fixtures/eslint-v9/package.json create mode 100644 fixtures/eslint-v9/yarn.lock delete mode 100644 fixtures/eslint/README.md delete mode 100644 fixtures/eslint/index.js delete mode 100644 fixtures/eslint/package.json delete mode 100644 fixtures/eslint/proxy/index.js delete mode 100644 fixtures/eslint/proxy/package.json delete mode 100755 fixtures/eslint/watch.sh delete mode 100644 fixtures/eslint/yarn.lock diff --git a/fixtures/eslint/.eslintrc.json b/fixtures/eslint-v6/.eslintrc.json similarity index 52% rename from fixtures/eslint/.eslintrc.json rename to fixtures/eslint-v6/.eslintrc.json index e03178a42a..33b2cfaaca 100644 --- a/fixtures/eslint/.eslintrc.json +++ b/fixtures/eslint-v6/.eslintrc.json @@ -1,15 +1,14 @@ { "root": true, + "extends": ["plugin:react-hooks/recommended-legacy"], "parserOptions": { - "ecmaVersion": 8, + "ecmaVersion": 2020, "sourceType": "module", "ecmaFeatures": { "jsx": true } }, - "plugins": ["react-hooks"], "rules": { - "react-hooks/rules-of-hooks": 2, - "react-hooks/exhaustive-deps": 2 + "react-hooks/exhaustive-deps": "error" } } diff --git a/fixtures/eslint-v6/README.md b/fixtures/eslint-v6/README.md new file mode 100644 index 0000000000..7f0ebe8b03 --- /dev/null +++ b/fixtures/eslint-v6/README.md @@ -0,0 +1,12 @@ +# ESLint v6 Fixture + +This fixture allows us to test e2e functionality for `eslint-plugin-react-hooks` with eslint version 6. + +Run the following to test. + +```sh +cd fixtures/eslint-v6 +yarn +yarn build +yarn lint +``` diff --git a/fixtures/eslint-v6/build.mjs b/fixtures/eslint-v6/build.mjs new file mode 100644 index 0000000000..02a1bbd25e --- /dev/null +++ b/fixtures/eslint-v6/build.mjs @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +import {exec} from 'node:child_process'; + +exec('cd ../.. && yarn build -r stable eslint-plugin-react-hooks'); diff --git a/fixtures/eslint-v6/index.js b/fixtures/eslint-v6/index.js new file mode 100644 index 0000000000..6d4a7235dd --- /dev/null +++ b/fixtures/eslint-v6/index.js @@ -0,0 +1,143 @@ +/** + * Exhaustive Deps + */ +// Valid because dependencies are declared correctly +function Comment({comment, commentSource}) { + const currentUserID = comment.viewer.id; + const environment = RelayEnvironment.forUser(currentUserID); + const commentID = nullthrows(comment.id); + useEffect(() => { + const subscription = SubscriptionCounter.subscribeOnce( + `StoreSubscription_${commentID}`, + () => + StoreSubscription.subscribe( + environment, + { + comment_id: commentID, + }, + currentUserID, + commentSource + ) + ); + return () => subscription.dispose(); + }, [commentID, commentSource, currentUserID, environment]); +} + +// Valid because no dependencies +function UseEffectWithNoDependencies() { + const local = {}; + useEffect(() => { + console.log(local); + }); +} +function UseEffectWithEmptyDependencies() { + useEffect(() => { + const local = {}; + console.log(local); + }, []); +} + +// OK because `props` wasn't defined. +function ComponentWithNoPropsDefined() { + useEffect(() => { + console.log(props.foo); + }, []); +} + +// Valid because props are declared as a dependency +function ComponentWithPropsDeclaredAsDep({foo}) { + useEffect(() => { + console.log(foo.length); + console.log(foo.slice(0)); + }, [foo]); +} + +// Valid because individual props are declared as dependencies +function ComponentWithIndividualPropsDeclaredAsDeps(props) { + useEffect(() => { + console.log(props.foo); + console.log(props.bar); + }, [props.bar, props.foo]); +} + +// Invalid because neither props or props.foo are declared as dependencies +function ComponentWithoutDeclaringPropAsDep(props) { + useEffect(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useCallback(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useMemo(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useEffect(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useCallback(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useMemo(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.notReactiveHook(() => { + console.log(props.foo); + }, []); // This one isn't a violation +} + +/** + * Rules of Hooks + */ +// Valid because functions can call functions. +function normalFunctionWithConditionalFunction() { + if (cond) { + doSomething(); + } +} + +// Valid because hooks can call hooks. +function useHook() { + useState(); +} +const whatever = function useHook() { + useState(); +}; +const useHook1 = () => { + useState(); +}; +let useHook2 = () => useState(); +useHook2 = () => { + useState(); +}; + +// Invalid because hooks can't be called in conditionals. +function ComponentWithConditionalHook() { + if (cond) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useConditionalHook(); + } +} + +// Invalid because hooks can't be called in loops. +function useHookInLoops() { + while (a) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook1(); + if (b) return; + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook2(); + } + while (c) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook3(); + if (d) return; + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook4(); + } +} diff --git a/fixtures/eslint-v6/package.json b/fixtures/eslint-v6/package.json new file mode 100644 index 0000000000..50c92054b4 --- /dev/null +++ b/fixtures/eslint-v6/package.json @@ -0,0 +1,12 @@ +{ + "private": true, + "name": "eslint-v6", + "dependencies": { + "eslint": "^6", + "eslint-plugin-react-hooks": "link:../../build/node_modules/eslint-plugin-react-hooks" + }, + "scripts": { + "build": "node build.mjs && yarn", + "lint": "eslint index.js --report-unused-disable-directives" + } +} diff --git a/fixtures/eslint-v6/yarn.lock b/fixtures/eslint-v6/yarn.lock new file mode 100644 index 0000000000..3d6dbca037 --- /dev/null +++ b/fixtures/eslint-v6/yarn.lock @@ -0,0 +1,865 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +acorn-jsx@^5.2.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +ajv@^6.10.0, ajv@^6.10.2: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^2.1.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +cross-spawn@^6.0.5: + version "6.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.6.tgz#30d0efa0712ddb7eb5a76e1e8721bffafa6b5d57" + integrity sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +debug@^4.0.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +"eslint-plugin-react-hooks@link:../../build/node_modules/eslint-plugin-react-hooks": + version "0.0.0" + uid "" + +eslint-scope@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint@^6: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" + integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.3" + eslint-visitor-keys "^1.1.0" + espree "^6.1.2" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.14" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.3" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^6.1.2: + version "6.2.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" + integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== + dependencies: + acorn "^7.1.1" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.1.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +glob-parent@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +import-fresh@^3.0.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +inquirer@^7.0.0: + version "7.3.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lodash@^4.17.14, lodash@^4.17.19: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== + +picocolors@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +rxjs@^6.6.0: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^5.5.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.1.2: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== + +signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +v8-compile-cache@^2.0.3: + version "2.4.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" + integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +word-wrap@~1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" diff --git a/fixtures/eslint-v7/.eslintrc.json b/fixtures/eslint-v7/.eslintrc.json new file mode 100644 index 0000000000..33b2cfaaca --- /dev/null +++ b/fixtures/eslint-v7/.eslintrc.json @@ -0,0 +1,14 @@ +{ + "root": true, + "extends": ["plugin:react-hooks/recommended-legacy"], + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true + } + }, + "rules": { + "react-hooks/exhaustive-deps": "error" + } +} diff --git a/fixtures/eslint-v7/README.md b/fixtures/eslint-v7/README.md new file mode 100644 index 0000000000..ea4628b0e0 --- /dev/null +++ b/fixtures/eslint-v7/README.md @@ -0,0 +1,12 @@ +# ESLint v7 Fixture + +This fixture allows us to test e2e functionality for `eslint-plugin-react-hooks` with eslint version 7. + +Run the following to test. + +```sh +cd fixtures/eslint-v7 +yarn +yarn build +yarn lint +``` diff --git a/fixtures/eslint-v7/build.mjs b/fixtures/eslint-v7/build.mjs new file mode 100644 index 0000000000..02a1bbd25e --- /dev/null +++ b/fixtures/eslint-v7/build.mjs @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +import {exec} from 'node:child_process'; + +exec('cd ../.. && yarn build -r stable eslint-plugin-react-hooks'); diff --git a/fixtures/eslint-v7/index.js b/fixtures/eslint-v7/index.js new file mode 100644 index 0000000000..6d4a7235dd --- /dev/null +++ b/fixtures/eslint-v7/index.js @@ -0,0 +1,143 @@ +/** + * Exhaustive Deps + */ +// Valid because dependencies are declared correctly +function Comment({comment, commentSource}) { + const currentUserID = comment.viewer.id; + const environment = RelayEnvironment.forUser(currentUserID); + const commentID = nullthrows(comment.id); + useEffect(() => { + const subscription = SubscriptionCounter.subscribeOnce( + `StoreSubscription_${commentID}`, + () => + StoreSubscription.subscribe( + environment, + { + comment_id: commentID, + }, + currentUserID, + commentSource + ) + ); + return () => subscription.dispose(); + }, [commentID, commentSource, currentUserID, environment]); +} + +// Valid because no dependencies +function UseEffectWithNoDependencies() { + const local = {}; + useEffect(() => { + console.log(local); + }); +} +function UseEffectWithEmptyDependencies() { + useEffect(() => { + const local = {}; + console.log(local); + }, []); +} + +// OK because `props` wasn't defined. +function ComponentWithNoPropsDefined() { + useEffect(() => { + console.log(props.foo); + }, []); +} + +// Valid because props are declared as a dependency +function ComponentWithPropsDeclaredAsDep({foo}) { + useEffect(() => { + console.log(foo.length); + console.log(foo.slice(0)); + }, [foo]); +} + +// Valid because individual props are declared as dependencies +function ComponentWithIndividualPropsDeclaredAsDeps(props) { + useEffect(() => { + console.log(props.foo); + console.log(props.bar); + }, [props.bar, props.foo]); +} + +// Invalid because neither props or props.foo are declared as dependencies +function ComponentWithoutDeclaringPropAsDep(props) { + useEffect(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useCallback(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useMemo(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useEffect(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useCallback(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useMemo(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.notReactiveHook(() => { + console.log(props.foo); + }, []); // This one isn't a violation +} + +/** + * Rules of Hooks + */ +// Valid because functions can call functions. +function normalFunctionWithConditionalFunction() { + if (cond) { + doSomething(); + } +} + +// Valid because hooks can call hooks. +function useHook() { + useState(); +} +const whatever = function useHook() { + useState(); +}; +const useHook1 = () => { + useState(); +}; +let useHook2 = () => useState(); +useHook2 = () => { + useState(); +}; + +// Invalid because hooks can't be called in conditionals. +function ComponentWithConditionalHook() { + if (cond) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useConditionalHook(); + } +} + +// Invalid because hooks can't be called in loops. +function useHookInLoops() { + while (a) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook1(); + if (b) return; + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook2(); + } + while (c) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook3(); + if (d) return; + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook4(); + } +} diff --git a/fixtures/eslint-v7/package.json b/fixtures/eslint-v7/package.json new file mode 100644 index 0000000000..90c369c603 --- /dev/null +++ b/fixtures/eslint-v7/package.json @@ -0,0 +1,12 @@ +{ + "private": true, + "name": "eslint-v7", + "dependencies": { + "eslint": "^7", + "eslint-plugin-react-hooks": "link:../../build/node_modules/eslint-plugin-react-hooks" + }, + "scripts": { + "build": "node build.mjs && yarn", + "lint": "eslint index.js --report-unused-disable-directives" + } +} diff --git a/fixtures/eslint-v7/yarn.lock b/fixtures/eslint-v7/yarn.lock new file mode 100644 index 0000000000..62f97bbc20 --- /dev/null +++ b/fixtures/eslint-v7/yarn.lock @@ -0,0 +1,769 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/highlight@^7.10.4": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.9.tgz#8141ce68fc73757946f983b343f1231f4691acc6" + integrity sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +cross-spawn@^7.0.2: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.0.1, debug@^4.1.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +enquirer@^2.3.5: + version "2.4.1" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +"eslint-plugin-react-hooks@link:../../build/node_modules/eslint-plugin-react-hooks": + version "0.0.0" + uid "" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint@^7: + version "7.32.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fast-uri@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748" + integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== + +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" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^13.6.0, globals@^13.9.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +optionator@^0.9.1: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +picocolors@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +semver@^7.2.1: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +table@^6.0.9: + version "6.9.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.9.0.tgz#50040afa6264141c7566b3b81d4d82c47a8668f5" + integrity sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +v8-compile-cache@^2.0.3: + version "2.4.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" + integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= diff --git a/fixtures/eslint-v8/.eslintrc.json b/fixtures/eslint-v8/.eslintrc.json new file mode 100644 index 0000000000..33b2cfaaca --- /dev/null +++ b/fixtures/eslint-v8/.eslintrc.json @@ -0,0 +1,14 @@ +{ + "root": true, + "extends": ["plugin:react-hooks/recommended-legacy"], + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true + } + }, + "rules": { + "react-hooks/exhaustive-deps": "error" + } +} diff --git a/fixtures/eslint-v8/README.md b/fixtures/eslint-v8/README.md new file mode 100644 index 0000000000..da220cef5c --- /dev/null +++ b/fixtures/eslint-v8/README.md @@ -0,0 +1,12 @@ +# ESLint v8 Fixture + +This fixture allows us to test e2e functionality for `eslint-plugin-react-hooks` with eslint version 8. + +Run the following to test. + +```sh +cd fixtures/eslint-v8 +yarn +yarn build +yarn lint +``` diff --git a/fixtures/eslint-v8/build.mjs b/fixtures/eslint-v8/build.mjs new file mode 100644 index 0000000000..02a1bbd25e --- /dev/null +++ b/fixtures/eslint-v8/build.mjs @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +import {exec} from 'node:child_process'; + +exec('cd ../.. && yarn build -r stable eslint-plugin-react-hooks'); diff --git a/fixtures/eslint-v8/index.js b/fixtures/eslint-v8/index.js new file mode 100644 index 0000000000..6d4a7235dd --- /dev/null +++ b/fixtures/eslint-v8/index.js @@ -0,0 +1,143 @@ +/** + * Exhaustive Deps + */ +// Valid because dependencies are declared correctly +function Comment({comment, commentSource}) { + const currentUserID = comment.viewer.id; + const environment = RelayEnvironment.forUser(currentUserID); + const commentID = nullthrows(comment.id); + useEffect(() => { + const subscription = SubscriptionCounter.subscribeOnce( + `StoreSubscription_${commentID}`, + () => + StoreSubscription.subscribe( + environment, + { + comment_id: commentID, + }, + currentUserID, + commentSource + ) + ); + return () => subscription.dispose(); + }, [commentID, commentSource, currentUserID, environment]); +} + +// Valid because no dependencies +function UseEffectWithNoDependencies() { + const local = {}; + useEffect(() => { + console.log(local); + }); +} +function UseEffectWithEmptyDependencies() { + useEffect(() => { + const local = {}; + console.log(local); + }, []); +} + +// OK because `props` wasn't defined. +function ComponentWithNoPropsDefined() { + useEffect(() => { + console.log(props.foo); + }, []); +} + +// Valid because props are declared as a dependency +function ComponentWithPropsDeclaredAsDep({foo}) { + useEffect(() => { + console.log(foo.length); + console.log(foo.slice(0)); + }, [foo]); +} + +// Valid because individual props are declared as dependencies +function ComponentWithIndividualPropsDeclaredAsDeps(props) { + useEffect(() => { + console.log(props.foo); + console.log(props.bar); + }, [props.bar, props.foo]); +} + +// Invalid because neither props or props.foo are declared as dependencies +function ComponentWithoutDeclaringPropAsDep(props) { + useEffect(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useCallback(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useMemo(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useEffect(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useCallback(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useMemo(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.notReactiveHook(() => { + console.log(props.foo); + }, []); // This one isn't a violation +} + +/** + * Rules of Hooks + */ +// Valid because functions can call functions. +function normalFunctionWithConditionalFunction() { + if (cond) { + doSomething(); + } +} + +// Valid because hooks can call hooks. +function useHook() { + useState(); +} +const whatever = function useHook() { + useState(); +}; +const useHook1 = () => { + useState(); +}; +let useHook2 = () => useState(); +useHook2 = () => { + useState(); +}; + +// Invalid because hooks can't be called in conditionals. +function ComponentWithConditionalHook() { + if (cond) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useConditionalHook(); + } +} + +// Invalid because hooks can't be called in loops. +function useHookInLoops() { + while (a) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook1(); + if (b) return; + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook2(); + } + while (c) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook3(); + if (d) return; + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook4(); + } +} diff --git a/fixtures/eslint-v8/package.json b/fixtures/eslint-v8/package.json new file mode 100644 index 0000000000..620520ecdb --- /dev/null +++ b/fixtures/eslint-v8/package.json @@ -0,0 +1,12 @@ +{ + "private": true, + "name": "eslint-v8", + "dependencies": { + "eslint": "^8", + "eslint-plugin-react-hooks": "link:../../build/node_modules/eslint-plugin-react-hooks" + }, + "scripts": { + "build": "node build.mjs && yarn", + "lint": "eslint index.js --report-unused-disable-directives" + } +} diff --git a/fixtures/eslint-v8/yarn.lock b/fixtures/eslint-v8/yarn.lock new file mode 100644 index 0000000000..88d0402995 --- /dev/null +++ b/fixtures/eslint-v8/yarn.lock @@ -0,0 +1,676 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.6.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== + dependencies: + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@ungap/structured-clone@^1.2.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.9.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +cross-spawn@^7.0.2: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.3.1, debug@^4.3.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +"eslint-plugin-react-hooks@link:../../build/node_modules/eslint-plugin-react-hooks": + version "0.0.0" + uid "" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8: + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.0.tgz#a82c6b7c2bb4e44766d865f07997785fecfdcb89" + integrity sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA== + dependencies: + reusify "^1.0.4" + +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" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +ignore@^5.2.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.0, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.0.5, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/fixtures/eslint-v9/README.md b/fixtures/eslint-v9/README.md new file mode 100644 index 0000000000..3ea521cfa8 --- /dev/null +++ b/fixtures/eslint-v9/README.md @@ -0,0 +1,12 @@ +# ESLint v9 Fixture + +This fixture allows us to test e2e functionality for `eslint-plugin-react-hooks` with eslint version 9. + +Run the following to test. + +```sh +cd fixtures/eslint-v9 +yarn +yarn build +yarn lint +``` diff --git a/fixtures/eslint-v9/build.mjs b/fixtures/eslint-v9/build.mjs new file mode 100644 index 0000000000..02a1bbd25e --- /dev/null +++ b/fixtures/eslint-v9/build.mjs @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +import {exec} from 'node:child_process'; + +exec('cd ../.. && yarn build -r stable eslint-plugin-react-hooks'); diff --git a/fixtures/eslint-v9/eslint.config.mjs b/fixtures/eslint-v9/eslint.config.mjs new file mode 100644 index 0000000000..ffc8375265 --- /dev/null +++ b/fixtures/eslint-v9/eslint.config.mjs @@ -0,0 +1,21 @@ +import * as reactHooks from 'eslint-plugin-react-hooks'; + +export default [ + { + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + }, + reactHooks.configs['recommended-latest'], + { + rules: { + 'react-hooks/exhaustive-deps': 'error', + }, + }, +]; diff --git a/fixtures/eslint-v9/index.js b/fixtures/eslint-v9/index.js new file mode 100644 index 0000000000..6d4a7235dd --- /dev/null +++ b/fixtures/eslint-v9/index.js @@ -0,0 +1,143 @@ +/** + * Exhaustive Deps + */ +// Valid because dependencies are declared correctly +function Comment({comment, commentSource}) { + const currentUserID = comment.viewer.id; + const environment = RelayEnvironment.forUser(currentUserID); + const commentID = nullthrows(comment.id); + useEffect(() => { + const subscription = SubscriptionCounter.subscribeOnce( + `StoreSubscription_${commentID}`, + () => + StoreSubscription.subscribe( + environment, + { + comment_id: commentID, + }, + currentUserID, + commentSource + ) + ); + return () => subscription.dispose(); + }, [commentID, commentSource, currentUserID, environment]); +} + +// Valid because no dependencies +function UseEffectWithNoDependencies() { + const local = {}; + useEffect(() => { + console.log(local); + }); +} +function UseEffectWithEmptyDependencies() { + useEffect(() => { + const local = {}; + console.log(local); + }, []); +} + +// OK because `props` wasn't defined. +function ComponentWithNoPropsDefined() { + useEffect(() => { + console.log(props.foo); + }, []); +} + +// Valid because props are declared as a dependency +function ComponentWithPropsDeclaredAsDep({foo}) { + useEffect(() => { + console.log(foo.length); + console.log(foo.slice(0)); + }, [foo]); +} + +// Valid because individual props are declared as dependencies +function ComponentWithIndividualPropsDeclaredAsDeps(props) { + useEffect(() => { + console.log(props.foo); + console.log(props.bar); + }, [props.bar, props.foo]); +} + +// Invalid because neither props or props.foo are declared as dependencies +function ComponentWithoutDeclaringPropAsDep(props) { + useEffect(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useCallback(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useMemo(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useEffect(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useCallback(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.useMemo(() => { + console.log(props.foo); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + React.notReactiveHook(() => { + console.log(props.foo); + }, []); // This one isn't a violation +} + +/** + * Rules of Hooks + */ +// Valid because functions can call functions. +function normalFunctionWithConditionalFunction() { + if (cond) { + doSomething(); + } +} + +// Valid because hooks can call hooks. +function useHook() { + useState(); +} +const whatever = function useHook() { + useState(); +}; +const useHook1 = () => { + useState(); +}; +let useHook2 = () => useState(); +useHook2 = () => { + useState(); +}; + +// Invalid because hooks can't be called in conditionals. +function ComponentWithConditionalHook() { + if (cond) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useConditionalHook(); + } +} + +// Invalid because hooks can't be called in loops. +function useHookInLoops() { + while (a) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook1(); + if (b) return; + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook2(); + } + while (c) { + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook3(); + if (d) return; + // eslint-disable-next-line react-hooks/rules-of-hooks + useHook4(); + } +} diff --git a/fixtures/eslint-v9/package.json b/fixtures/eslint-v9/package.json new file mode 100644 index 0000000000..e8ae91a061 --- /dev/null +++ b/fixtures/eslint-v9/package.json @@ -0,0 +1,12 @@ +{ + "private": true, + "name": "eslint-v9", + "dependencies": { + "eslint": "^9", + "eslint-plugin-react-hooks": "link:../../build/node_modules/eslint-plugin-react-hooks" + }, + "scripts": { + "build": "node build.mjs && yarn", + "lint": "eslint index.js --report-unused-disable-directives" + } +} diff --git a/fixtures/eslint-v9/yarn.lock b/fixtures/eslint-v9/yarn.lock new file mode 100644 index 0000000000..5a1a246827 --- /dev/null +++ b/fixtures/eslint-v9/yarn.lock @@ -0,0 +1,579 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/config-array@^0.19.0": + version "0.19.2" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa" + integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w== + dependencies: + "@eslint/object-schema" "^2.1.6" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.10.0.tgz#23727063c21b335f752dbb3a16450f6f9cbc9091" + integrity sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/core@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.11.0.tgz#7a9226e850922e42cbd2ba71361eacbe74352a12" + integrity sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c" + integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@9.20.0": + version "9.20.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.20.0.tgz#7421bcbe74889fcd65d1be59f00130c289856eb4" + integrity sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ== + +"@eslint/object-schema@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f" + integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA== + +"@eslint/plugin-kit@^0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz#ee07372035539e7847ef834e3f5e7b79f09e3a81" + integrity sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A== + dependencies: + "@eslint/core" "^0.10.0" + levn "^0.4.1" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b" + integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA== + +"@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.14.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.3.1, debug@^4.3.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +"eslint-plugin-react-hooks@link:../../build/node_modules/eslint-plugin-react-hooks": + version "0.0.0" + uid "" + +eslint-scope@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442" + integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" + integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== + +eslint@^9: + version "9.20.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.20.1.tgz#923924c078f5226832449bac86662dd7e53c91d6" + integrity sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.19.0" + "@eslint/core" "^0.11.0" + "@eslint/eslintrc" "^3.2.0" + "@eslint/js" "9.20.0" + "@eslint/plugin-kit" "^0.2.5" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.2.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +espree@^10.0.1, espree@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" + integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== + dependencies: + acorn "^8.14.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.0" + +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flatted@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +ignore@^5.2.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.0, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/fixtures/eslint/README.md b/fixtures/eslint/README.md deleted file mode 100644 index 28ab225513..0000000000 --- a/fixtures/eslint/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# ESLint Playground Fixture - -This is an internal playground for quick iteration on our lint rules inside an IDE like VSCode. - -See instructions in `./index.js` in this directory. - -![Demo](https://duaw26jehqd4r.cloudfront.net/items/2Z390a31003O0l0o0e3O/Screen%20Recording%202019-01-16%20at%2010.29%20PM.gif?v=d6856125) \ No newline at end of file diff --git a/fixtures/eslint/index.js b/fixtures/eslint/index.js deleted file mode 100644 index d534153105..0000000000 --- a/fixtures/eslint/index.js +++ /dev/null @@ -1,26 +0,0 @@ -// This is a testing playground for our lint rules. - -// 1. Run yarn && yarn start -// 2. "File > Add Folder to Workspace" this specific folder in VSCode with ESLint extension -// 3. Changes to the rule source should get picked up without restarting ESLint server - -function Comment({comment, commentSource}) { - const currentUserID = comment.viewer.id; - const environment = RelayEnvironment.forUser(currentUserID); - const commentID = nullthrows(comment.id); - useEffect(() => { - const subscription = SubscriptionCounter.subscribeOnce( - `StoreSubscription_${commentID}`, - () => - StoreSubscription.subscribe( - environment, - { - comment_id: commentID, - }, - currentUserID, - commentSource - ) - ); - return () => subscription.dispose(); - }, [commentID, commentSource, currentUserID, environment]); -} diff --git a/fixtures/eslint/package.json b/fixtures/eslint/package.json deleted file mode 100644 index 04f8d6b98b..0000000000 --- a/fixtures/eslint/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "private": true, - "name": "eslint-playground", - "dependencies": { - "eslint": "4.1.0", - "eslint-plugin-react-hooks": "link:./proxy" - }, - "scripts": { - "start": "./watch.sh", - "lint": "eslint index.js" - } -} diff --git a/fixtures/eslint/proxy/index.js b/fixtures/eslint/proxy/index.js deleted file mode 100644 index f54e672d21..0000000000 --- a/fixtures/eslint/proxy/index.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -// This file is a proxy for our rule definition that will -// load the latest built version on every check. This makes -// it convenient to test inside IDEs (which would otherwise -// load a version of our rule once and never restart the server). -// See instructions in ../index.js playground. - -let build; -reload(); - -function reload() { - for (let id in require.cache) { - if (/eslint-plugin-react-hooks/.test(id)) { - delete require.cache[id]; - } - } - // Point to the built version. - build = require('../../../build/oss-experimental/eslint-plugin-react-hooks'); -} - -let rules = {}; -for (let key in build.rules) { - if (build.rules.hasOwnProperty(key)) { - rules[key] = Object.assign({}, build.rules, { - create() { - // Reload changes to the built rule - reload(); - return build.rules[key].create.apply(this, arguments); - }, - }); - } -} - -module.exports = {rules}; diff --git a/fixtures/eslint/proxy/package.json b/fixtures/eslint/proxy/package.json deleted file mode 100644 index 1461c2d43f..0000000000 --- a/fixtures/eslint/proxy/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "private": true, - "version": "0.0.0" -} \ No newline at end of file diff --git a/fixtures/eslint/watch.sh b/fixtures/eslint/watch.sh deleted file mode 100755 index 0ca6359c03..0000000000 --- a/fixtures/eslint/watch.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -(cd ../.. && yarn build eslint --type=NODE_DEV) -(cd ../.. && watchman-make --make 'yarn build eslint --type=NODE_DEV' -p 'packages/eslint-plugin-*/**/*' -t ignored) diff --git a/fixtures/eslint/yarn.lock b/fixtures/eslint/yarn.lock deleted file mode 100644 index 7a557036da..0000000000 --- a/fixtures/eslint/yarn.lock +++ /dev/null @@ -1,853 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s= - dependencies: - acorn "^3.0.4" - -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= - -acorn@^5.5.0: - version "5.7.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" - integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== - -ajv-keywords@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" - integrity sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo= - -ajv@^6.0.1: - version "6.7.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.7.0.tgz#e3ce7bb372d6577bb1839f1dfdfcbf5ad2948d96" - integrity sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-escapes@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" - integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -babel-code-frame@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= - dependencies: - callsites "^0.2.0" - -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.1.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" - integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= - -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@^1.6.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -debug@^2.6.8: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -doctrine@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -"eslint-plugin-react-hooks@link:./proxy": - version "0.0.0" - uid "" - -eslint-scope@^3.7.1: - version "3.7.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" - integrity sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.1.0.tgz#bbb55a28220ee08b69da9554d45a6b2ebfd7d913" - integrity sha1-u7VaKCIO4Itp2pVU1FprLr/X2RM= - dependencies: - babel-code-frame "^6.22.0" - chalk "^1.1.3" - concat-stream "^1.6.0" - debug "^2.6.8" - doctrine "^2.0.0" - eslint-scope "^3.7.1" - espree "^3.4.3" - esquery "^1.0.0" - estraverse "^4.2.0" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - glob "^7.1.2" - globals "^9.17.0" - ignore "^3.3.3" - imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-my-json-valid "^2.16.0" - is-resolvable "^1.0.0" - js-yaml "^3.8.4" - json-stable-stringify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - pluralize "^4.0.0" - progress "^2.0.0" - require-uncached "^1.0.3" - strip-json-comments "~2.0.1" - table "^4.0.1" - text-table "~0.2.0" - -espree@^3.4.3: - version "3.5.4" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" - integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A== - dependencies: - acorn "^5.5.0" - acorn-jsx "^3.0.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" - integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== - dependencies: - estraverse "^4.0.0" - -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== - dependencies: - estraverse "^4.1.0" - -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= - -external-editor@^2.0.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" - integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== - dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" - tmp "^0.0.33" - -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - -fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E= - dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" - -flat-cache@^1.2.1: - version "1.3.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f" - integrity sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg== - dependencies: - circular-json "^0.3.1" - graceful-fs "^4.1.2" - rimraf "~2.6.2" - write "^0.2.1" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -generate-function@^2.0.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" - integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== - dependencies: - is-property "^1.0.2" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - integrity sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA= - dependencies: - is-property "^1.0.0" - -glob@^7.1.2, glob@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^9.17.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== - -graceful-fs@^4.1.2: - version "4.1.15" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" - integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -iconv-lite@^0.4.17: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ignore@^3.3.3: - version "3.3.10" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.3, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -inquirer@^3.0.6: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" - integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.4" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-my-ip-valid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" - integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ== - -is-my-json-valid@^2.16.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175" - integrity sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q== - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - is-my-ip-valid "^1.0.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= - -is-property@^1.0.0, is-property@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= - -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= - -js-yaml@^3.8.4: - version "3.12.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600" - integrity sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - dependencies: - jsonify "~0.0.0" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= - -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - integrity sha1-T9kss04OnbPInIYi7PUfm5eMbLk= - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -lodash@^4.17.4, lodash@^4.3.0: - version "4.17.11" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -minimatch@^3.0.2, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - -mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - dependencies: - minimist "0.0.8" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - -optionator@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -pluralize@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-4.0.0.tgz#59b708c1c0190a2f692f1c7618c446b052fd1762" - integrity sha1-WbcIwcAZCi9pLxx2GMRGsFL9F2I= - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -readable-stream@^2.2.2: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -require-uncached@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -rimraf@~2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= - dependencies: - is-promise "^2.1.0" - -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= - -slice-ansi@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" - integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== - dependencies: - is-fullwidth-code-point "^2.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -string-width@^2.1.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -table@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" - integrity sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg== - dependencies: - ajv "^6.0.1" - ajv-keywords "^3.0.0" - chalk "^2.1.0" - lodash "^4.17.4" - slice-ansi "1.0.0" - string-width "^2.1.1" - -text-table@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= - dependencies: - mkdirp "^0.5.1" - -xtend@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= From 5adf40208f4a2f56bda5c059d18ce578c5091dab Mon Sep 17 00:00:00 2001 From: michael faith Date: Sun, 16 Feb 2025 13:10:54 -0600 Subject: [PATCH 03/13] feat(eslint-plugin-react-hooks): convert to typescript and package type declarations (#32240) ## Summary This change converts the eslint hooks plugin to typescript, which also allows us to include type declarations in the package, for those using [typescript eslint configs](https://eslint.org/blog/2025/01/eslint-v9.18.0-released/#stable-typescript-configuration-file-support). ### Constituent changes that should land before this one - [x] ~https://github.com/facebook/react/pull/32276~ - [x] https://github.com/facebook/react/pull/32279 - [x] https://github.com/facebook/react/pull/32283 - [x] https://github.com/facebook/react/pull/32393 - [x] https://github.com/facebook/react/pull/32396 Closes #30119 --------- Co-authored-by: Lauren Tan --- .../eslint-plugin-react-hooks/babel.config.js | 8 + packages/eslint-plugin-react-hooks/index.js | 9 +- .../eslint-plugin-react-hooks/jest.config.js | 8 + .../eslint-plugin-react-hooks/npm/index.d.ts | 1 + .../eslint-plugin-react-hooks/package.json | 11 +- .../{ExhaustiveDeps.js => ExhaustiveDeps.ts} | 631 +++++++++++------- .../src/{RulesOfHooks.js => RulesOfHooks.ts} | 145 ++-- .../eslint-plugin-react-hooks/src/index.js | 61 -- .../eslint-plugin-react-hooks/src/index.ts | 64 ++ .../src/types/estree.d.ts | 2 + .../eslint-plugin-react-hooks/tsconfig.json | 1 - .../eslint-plugin-react-hooks/tsup.config.ts | 9 - scripts/rollup/bundles.js | 14 +- yarn.lock | 467 +------------ 14 files changed, 574 insertions(+), 857 deletions(-) create mode 100644 packages/eslint-plugin-react-hooks/babel.config.js create mode 100644 packages/eslint-plugin-react-hooks/jest.config.js create mode 100644 packages/eslint-plugin-react-hooks/npm/index.d.ts rename packages/eslint-plugin-react-hooks/src/{ExhaustiveDeps.js => ExhaustiveDeps.ts} (78%) rename packages/eslint-plugin-react-hooks/src/{RulesOfHooks.js => RulesOfHooks.ts} (85%) delete mode 100644 packages/eslint-plugin-react-hooks/src/index.js create mode 100644 packages/eslint-plugin-react-hooks/src/index.ts delete mode 100644 packages/eslint-plugin-react-hooks/tsup.config.ts diff --git a/packages/eslint-plugin-react-hooks/babel.config.js b/packages/eslint-plugin-react-hooks/babel.config.js new file mode 100644 index 0000000000..3b947a7163 --- /dev/null +++ b/packages/eslint-plugin-react-hooks/babel.config.js @@ -0,0 +1,8 @@ +/** + * This file is purely being used for local jest runs, and doesn't participate in the build process. + */ +'use strict'; + +module.exports = { + extends: '../../babel.config-ts.js', +}; diff --git a/packages/eslint-plugin-react-hooks/index.js b/packages/eslint-plugin-react-hooks/index.js index 754dc9f9c7..ce26a10c31 100644 --- a/packages/eslint-plugin-react-hooks/index.js +++ b/packages/eslint-plugin-react-hooks/index.js @@ -1,8 +1 @@ -/** - * 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. - */ - -export * from './src/index'; +module.exports = require('./src/index.ts'); diff --git a/packages/eslint-plugin-react-hooks/jest.config.js b/packages/eslint-plugin-react-hooks/jest.config.js new file mode 100644 index 0000000000..a7b91c3ef1 --- /dev/null +++ b/packages/eslint-plugin-react-hooks/jest.config.js @@ -0,0 +1,8 @@ +'use strict'; + +process.env.NODE_ENV = 'development'; + +module.exports = { + setupFiles: [require.resolve('../../scripts/jest/setupEnvironment.js')], + moduleFileExtensions: ['ts', 'js', 'json'], +}; diff --git a/packages/eslint-plugin-react-hooks/npm/index.d.ts b/packages/eslint-plugin-react-hooks/npm/index.d.ts new file mode 100644 index 0000000000..62ca164ec2 --- /dev/null +++ b/packages/eslint-plugin-react-hooks/npm/index.d.ts @@ -0,0 +1 @@ +export * from './cjs/eslint-plugin-react-hooks'; diff --git a/packages/eslint-plugin-react-hooks/package.json b/packages/eslint-plugin-react-hooks/package.json index b45609362f..d3717b9dee 100644 --- a/packages/eslint-plugin-react-hooks/package.json +++ b/packages/eslint-plugin-react-hooks/package.json @@ -10,8 +10,9 @@ "files": [ "LICENSE", "README.md", + "cjs", "index.js", - "cjs" + "index.d.ts" ], "keywords": [ "eslint", @@ -19,10 +20,16 @@ "eslintplugin", "react" ], + "scripts": { + "test": "jest", + "typecheck": "tsc --noEmit" + }, "license": "MIT", "bugs": { "url": "https://github.com/facebook/react/issues" }, + "main": "./index.js", + "types": "./index.d.ts", "engines": { "node": ">=10" }, @@ -32,6 +39,7 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.11.4", + "@babel/preset-typescript": "^7.26.0", "@tsconfig/strictest": "^2.0.5", "@typescript-eslint/parser-v2": "npm:@typescript-eslint/parser@^2.26.0", "@typescript-eslint/parser-v3": "npm:@typescript-eslint/parser@^3.10.0", @@ -45,7 +53,6 @@ "eslint-v7": "npm:eslint@^7.7.0", "eslint-v9": "npm:eslint@^9.0.0", "jest": "^29.5.0", - "tsup": "^8.3.5", "typescript": "^5.4.3" } } diff --git a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.ts similarity index 78% rename from packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js rename to packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.ts index b2818327ff..9f3d4d4db9 100644 --- a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js +++ b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.ts @@ -4,12 +4,41 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ - /* eslint-disable no-for-of-loops/no-for-of-loops */ +import type {Rule, Scope} from 'eslint'; +import type { + ArrayExpression, + ArrowFunctionExpression, + CallExpression, + Expression, + FunctionDeclaration, + FunctionExpression, + Identifier, + Node, + Pattern, + PrivateIdentifier, + Super, + VariableDeclarator, +} from 'estree'; -'use strict'; +type DeclaredDependency = { + key: string; + node: Node; +}; -export default { +type Dependency = { + isStable: boolean; + references: Scope.Reference[]; +}; + +type DependencyTreeNode = { + isUsed: boolean; // True if used in code + isSatisfiedRecursively: boolean; // True if specified in deps + isSubtreeUsed: boolean; // True if something deeper is used by code + children: Map; // Nodes for properties +}; + +const rule = { meta: { type: 'suggestion', docs: { @@ -36,7 +65,7 @@ export default { }, ], }, - create(context) { + create(context: Rule.RuleContext) { // Parse the `additionalHooks` regex. const additionalHooks = context.options && @@ -45,7 +74,7 @@ export default { ? new RegExp(context.options[0].additionalHooks) : undefined; - const enableDangerousAutofixThisMayCauseInfiniteLoops = + const enableDangerousAutofixThisMayCauseInfiniteLoops: boolean = (context.options && context.options[0] && context.options[0].enableDangerousAutofixThisMayCauseInfiniteLoops) || @@ -56,11 +85,15 @@ export default { enableDangerousAutofixThisMayCauseInfiniteLoops, }; - function reportProblem(problem) { + function reportProblem(problem: Rule.ReportDescriptor) { if (enableDangerousAutofixThisMayCauseInfiniteLoops) { // Used to enable legacy behavior. Dangerous. // Keep this as an option until major IDEs upgrade (including VSCode FB ESLint extension). - if (Array.isArray(problem.suggest) && problem.suggest.length > 0) { + if ( + Array.isArray(problem.suggest) && + problem.suggest.length > 0 && + problem.suggest[0] + ) { problem.fix = problem.suggest[0].fix; } } @@ -68,15 +101,15 @@ export default { } /** - * SourceCode#getText that also works down to ESLint 3.0.0 + * SourceCode that also works down to ESLint 3.0.0 */ - const getSource = - typeof context.getSource === 'function' - ? node => { - return context.getSource(node); + const getSourceCode = + typeof context.getSourceCode === 'function' + ? () => { + return context.getSourceCode(); } - : node => { - return context.sourceCode.getText(node); + : () => { + return context.sourceCode; }; /** * SourceCode#getScope that also works down to ESLint 3.0.0 @@ -86,24 +119,34 @@ export default { ? () => { return context.getScope(); } - : node => { + : (node: Node) => { return context.sourceCode.getScope(node); }; - const scopeManager = context.getSourceCode().scopeManager; + const scopeManager = getSourceCode().scopeManager; // Should be shared between visitors. - const setStateCallSites = new WeakMap(); - const stateVariables = new WeakSet(); - const stableKnownValueCache = new WeakMap(); - const functionWithoutCapturedValueCache = new WeakMap(); - const useEffectEventVariables = new WeakSet(); - function memoizeWithWeakMap(fn, map) { - return function (arg) { + const setStateCallSites = new WeakMap< + Expression | Super, + Pattern | null | undefined + >(); + const stateVariables = new WeakSet(); + const stableKnownValueCache = new WeakMap(); + const functionWithoutCapturedValueCache = new WeakMap< + Scope.Variable, + boolean + >(); + const useEffectEventVariables = new WeakSet(); + + function memoizeWithWeakMap( + fn: (resolved: Scope.Variable) => boolean, + map: WeakMap, + ) { + return function (arg: Scope.Variable): boolean { if (map.has(arg)) { // to verify cache hits: // console.log(arg.name) - return map.get(arg); + return map.get(arg)!; } const result = fn(arg); map.set(arg, result); @@ -114,12 +157,12 @@ export default { * Visitor for both function expressions and arrow function expressions. */ function visitFunctionWithDependencies( - node, - declaredDependenciesNode, - reactiveHook, - reactiveHookName, - isEffect, - ) { + node: ArrowFunctionExpression | FunctionDeclaration | FunctionExpression, + declaredDependenciesNode: Node | undefined, + reactiveHook: Node, + reactiveHookName: string, + isEffect: boolean, + ): void { if (isEffect && node.async) { reportProblem({ node: node, @@ -140,6 +183,9 @@ export default { // Get the current scope. const scope = scopeManager.acquire(node); + if (!scope) { + return; + } // Find all our "pure scopes". On every re-render of a component these // pure scopes may have changes to the variables declared within. So all @@ -150,7 +196,7 @@ export default { // scope. We can't enforce this in a lint so we trust that all variables // declared outside of pure scope are indeed frozen. const pureScopes = new Set(); - let componentScope = null; + let componentScope: Scope.Scope | null = null; { let currentScope = scope.upper; while (currentScope) { @@ -186,7 +232,7 @@ export default { // const onStuff = useEffectEvent(() => {}) // ^^^ true for this reference // False for everything else. - function isStableKnownHookValue(resolved) { + function isStableKnownHookValue(resolved: Scope.Variable): boolean { if (!isArray(resolved.defs)) { return false; } @@ -195,10 +241,11 @@ export default { return false; } // Look for `let stuff = ...` - if (def.node.type !== 'VariableDeclarator') { + const defNode: VariableDeclarator = def.node; + if (defNode.type !== 'VariableDeclarator') { return false; } - let init = def.node.init; + let init = defNode.init; if (init == null) { return false; } @@ -207,8 +254,8 @@ export default { } // Detect primitive constants // const foo = 42 - let declaration = def.node.parent; - if (declaration == null) { + let declaration = defNode.parent; + if (declaration == null && componentScope) { // This might happen if variable is declared after the callback. // In that case ESLint won't set up .parent refs. // So we'll set them up manually. @@ -219,6 +266,8 @@ export default { } } if ( + declaration && + 'kind' in declaration && declaration.kind === 'const' && init.type === 'Literal' && (typeof init.value === 'string' || @@ -233,10 +282,11 @@ export default { if (init.type !== 'CallExpression') { return false; } - let callee = init.callee; + let callee: Expression | PrivateIdentifier | Super = init.callee; // Step into `= React.something` initializer. if ( callee.type === 'MemberExpression' && + 'name' in callee.object && callee.object.name === 'React' && callee.property != null && !callee.computed @@ -246,7 +296,8 @@ export default { if (callee.type !== 'Identifier') { return false; } - const id = def.node.id; + const definitionNode: VariableDeclarator = def.node; + const id = definitionNode.id; const {name} = callee; if (name === 'useRef' && id.type === 'Identifier') { // useRef() return value is stable. @@ -256,6 +307,7 @@ export default { id.type === 'Identifier' ) { for (const ref of resolved.references) { + // @ts-expect-error These types are not compatible (Reference and Identifier) if (ref !== id) { useEffectEventVariables.add(ref.identifier); } @@ -278,17 +330,14 @@ export default { if (name === 'useState') { const references = resolved.references; let writeCount = 0; - for (let i = 0; i < references.length; i++) { - if (references[i].isWrite()) { + for (const reference of references) { + if (reference.isWrite()) { writeCount++; } if (writeCount > 1) { return false; } - setStateCallSites.set( - references[i].identifier, - id.elements[0], - ); + setStateCallSites.set(reference.identifier, id.elements[0]); } } // Setter is stable. @@ -296,8 +345,8 @@ export default { } else if (id.elements[0] === resolved.identifiers[0]) { if (name === 'useState') { const references = resolved.references; - for (let i = 0; i < references.length; i++) { - stateVariables.add(references[i].identifier); + for (const reference of references) { + stateVariables.add(reference.identifier); } } // State variable itself is dynamic. @@ -323,7 +372,9 @@ export default { } // Some are just functions that don't reference anything dynamic. - function isFunctionWithoutCapturedValues(resolved) { + function isFunctionWithoutCapturedValues( + resolved: Scope.Variable, + ): boolean { if (!isArray(resolved.defs)) { return false; } @@ -336,12 +387,10 @@ export default { } // Search the direct component subscopes for // top-level function definitions matching this reference. - const fnNode = def.node; - const childScopes = componentScope.childScopes; + const fnNode: Node = def.node; + const childScopes = componentScope?.childScopes || []; let fnScope = null; - let i; - for (i = 0; i < childScopes.length; i++) { - const childScope = childScopes[i]; + for (const childScope of childScopes) { const childScopeBlock = childScope.block; if ( // function handleChange() {} @@ -362,8 +411,7 @@ export default { } // Does this function capture any values // that are in pure scopes (aka render)? - for (i = 0; i < fnScope.through.length; i++) { - const ref = fnScope.through[i]; + for (const ref of fnScope.through) { if (ref.resolved == null) { continue; } @@ -392,15 +440,21 @@ export default { ); // These are usually mistaken. Collect them. - const currentRefsInEffectCleanup = new Map(); + const currentRefsInEffectCleanup = new Map< + string, + { + reference: Scope.Reference; + dependencyNode: Identifier; + } + >(); // Is this reference inside a cleanup function for this effect node? // We can check by traversing scopes upwards from the reference, and checking // if the last "return () => " we encounter is located directly inside the effect. - function isInsideEffectCleanup(reference) { - let curScope = reference.from; + function isInsideEffectCleanup(reference: Scope.Reference): boolean { + let curScope: Scope.Scope | null = reference.from; let isInReturnedFunction = false; - while (curScope.block !== node) { + while (curScope && curScope.block !== node) { if (curScope.type === 'function') { isInReturnedFunction = curScope.block.parent != null && @@ -413,11 +467,11 @@ export default { // Get dependencies from all our resolved references in pure scopes. // Key is dependency string, value is whether it's stable. - const dependencies = new Map(); - const optionalChains = new Map(); + const dependencies = new Map(); + const optionalChains = new Map(); gatherDependenciesRecursively(scope); - function gatherDependenciesRecursively(currentScope) { + function gatherDependenciesRecursively(currentScope: Scope.Scope): void { for (const reference of currentScope.references) { // If this reference is not resolved or it is not declared in a pure // scope then we don't care about this reference. @@ -434,6 +488,9 @@ export default { node, reference.identifier, ); + if (referenceNode == null) { + continue; + } const dependencyNode = getDependency(referenceNode); const dependency = analyzePropertyChain( dependencyNode, @@ -446,8 +503,8 @@ export default { isEffect && // ... and this look like accessing .current... dependencyNode.type === 'Identifier' && - (dependencyNode.parent.type === 'MemberExpression' || - dependencyNode.parent.type === 'OptionalMemberExpression') && + (dependencyNode.parent?.type === 'MemberExpression' || + dependencyNode.parent?.type === 'OptionalMemberExpression') && !dependencyNode.parent.computed && dependencyNode.parent.property.type === 'Identifier' && dependencyNode.parent.property.name === 'current' && @@ -461,8 +518,8 @@ export default { } if ( - dependencyNode.parent.type === 'TSTypeQuery' || - dependencyNode.parent.type === 'TSTypeReference' + dependencyNode.parent?.type === 'TSTypeQuery' || + dependencyNode.parent?.type === 'TSTypeReference' ) { continue; } @@ -472,10 +529,11 @@ export default { continue; } // Ignore references to the function itself as it's not defined yet. - if (def.node != null && def.node.init === node.parent) { + if (def.node && def.node.init === node.parent) { continue; } // Ignore Flow type parameters + // @ts-expect-error We don't have flow types if (def.type === 'TypeParameter') { continue; } @@ -492,7 +550,7 @@ export default { references: [reference], }); } else { - dependencies.get(dependency).references.push(reference); + dependencies.get(dependency)?.references.push(reference); } } @@ -504,12 +562,12 @@ export default { // Warn about accessing .current in cleanup effects. currentRefsInEffectCleanup.forEach( ({reference, dependencyNode}, dependency) => { - const references = reference.resolved.references; + const references = reference.resolved?.references || []; // Is React managing this ref or us? // Let's see if we can find a .current assignment. let foundCurrentAssignment = false; - for (let i = 0; i < references.length; i++) { - const {identifier} = references[i]; + for (const reference of references) { + const {identifier} = reference; const {parent} = identifier; if ( parent != null && @@ -520,7 +578,7 @@ export default { parent.property.type === 'Identifier' && parent.property.name === 'current' && // ref.current = - parent.parent.type === 'AssignmentExpression' && + parent.parent?.type === 'AssignmentExpression' && parent.parent.left === parent ) { foundCurrentAssignment = true; @@ -532,6 +590,7 @@ export default { return; } reportProblem({ + // @ts-expect-error We can do better here (dependencyNode.parent has not been type narrowed) node: dependencyNode.parent.property, message: `The ref value '${dependency}.current' will likely have ` + @@ -545,8 +604,8 @@ export default { // Warn about assigning to variables in the outer scope. // Those are usually bugs. - const staleAssignments = new Set(); - function reportStaleAssignment(writeExpr, key) { + const staleAssignments = new Set(); + function reportStaleAssignment(writeExpr: Node, key: string): void { if (staleAssignments.has(key)) { return; } @@ -555,16 +614,16 @@ export default { node: writeExpr, message: `Assignments to the '${key}' variable from inside React Hook ` + - `${getSource(reactiveHook)} will be lost after each ` + + `${getSourceCode().getText(reactiveHook)} will be lost after each ` + `render. To preserve the value over time, store it in a useRef ` + `Hook and keep the mutable value in the '.current' property. ` + `Otherwise, you can move this variable directly inside ` + - `${getSource(reactiveHook)}.`, + `${getSourceCode().getText(reactiveHook)}.`, }); } // Remember which deps are stable and report bad usage first. - const stableDependencies = new Set(); + const stableDependencies = new Set(); dependencies.forEach(({isStable, references}, key) => { if (isStable) { stableDependencies.add(key); @@ -584,8 +643,8 @@ export default { if (!declaredDependenciesNode) { // Check if there are any top-level setState() calls. // Those tend to lead to infinite loops. - let setStateInsideEffectWithoutDeps = null; - dependencies.forEach(({isStable, references}, key) => { + let setStateInsideEffectWithoutDeps: string | null = null; + dependencies.forEach(({references}, key) => { if (setStateInsideEffectWithoutDeps) { return; } @@ -600,11 +659,11 @@ export default { return; } - let fnScope = reference.from; - while (fnScope.type !== 'function') { + let fnScope: Scope.Scope | null = reference.from; + while (fnScope && fnScope.type !== 'function') { fnScope = fnScope.upper; } - const isDirectlyInsideEffect = fnScope.block === node; + const isDirectlyInsideEffect = fnScope?.block === node; if (isDirectlyInsideEffect) { // TODO: we could potentially ignore early returns. setStateInsideEffectWithoutDeps = key; @@ -616,7 +675,7 @@ export default { dependencies, declaredDependencies: [], stableDependencies, - externalDependencies: new Set(), + externalDependencies: new Set(), isEffect: true, }); reportProblem({ @@ -645,8 +704,8 @@ export default { return; } - const declaredDependencies = []; - const externalDependencies = new Set(); + const declaredDependencies: DeclaredDependency[] = []; + const externalDependencies = new Set(); const isArrayExpression = declaredDependenciesNode.type === 'ArrayExpression'; const isTSAsArrayExpression = @@ -660,7 +719,7 @@ export default { reportProblem({ node: declaredDependenciesNode, message: - `React Hook ${getSource(reactiveHook)} was passed a ` + + `React Hook ${getSourceCode().getText(reactiveHook)} was passed a ` + 'dependency list that is not an array literal. This means we ' + "can't statically verify whether you've passed the correct " + 'dependencies.', @@ -670,108 +729,117 @@ export default { ? declaredDependenciesNode.expression : declaredDependenciesNode; - arrayExpression.elements.forEach(declaredDependencyNode => { - // Skip elided elements. - if (declaredDependencyNode === null) { - return; - } - // If we see a spread element then add a special warning. - if (declaredDependencyNode.type === 'SpreadElement') { - reportProblem({ - node: declaredDependencyNode, - message: - `React Hook ${getSource(reactiveHook)} has a spread ` + - "element in its dependency array. This means we can't " + - "statically verify whether you've passed the " + - 'correct dependencies.', - }); - return; - } - if (useEffectEventVariables.has(declaredDependencyNode)) { - reportProblem({ - node: declaredDependencyNode, - message: - 'Functions returned from `useEffectEvent` must not be included in the dependency array. ' + - `Remove \`${getSource( - declaredDependencyNode, - )}\` from the list.`, - suggest: [ - { - desc: `Remove the dependency \`${getSource( + (arrayExpression as ArrayExpression).elements.forEach( + declaredDependencyNode => { + // Skip elided elements. + if (declaredDependencyNode === null) { + return; + } + // If we see a spread element then add a special warning. + if (declaredDependencyNode.type === 'SpreadElement') { + reportProblem({ + node: declaredDependencyNode, + message: + `React Hook ${getSourceCode().getText(reactiveHook)} has a spread ` + + "element in its dependency array. This means we can't " + + "statically verify whether you've passed the " + + 'correct dependencies.', + }); + return; + } + if (useEffectEventVariables.has(declaredDependencyNode)) { + reportProblem({ + node: declaredDependencyNode, + message: + 'Functions returned from `useEffectEvent` must not be included in the dependency array. ' + + `Remove \`${getSourceCode().getText( declaredDependencyNode, - )}\``, - fix(fixer) { - return fixer.removeRange(declaredDependencyNode.range); + )}\` from the list.`, + suggest: [ + { + desc: `Remove the dependency \`${getSourceCode().getText( + declaredDependencyNode, + )}\``, + fix(fixer) { + return fixer.removeRange(declaredDependencyNode.range!); + }, }, - }, - ], - }); - } - // Try to normalize the declared dependency. If we can't then an error - // will be thrown. We will catch that error and report an error. - let declaredDependency; - try { - declaredDependency = analyzePropertyChain( - declaredDependencyNode, - null, - ); - } catch (error) { - if (/Unsupported node type/.test(error.message)) { - if (declaredDependencyNode.type === 'Literal') { - if (dependencies.has(declaredDependencyNode.value)) { - reportProblem({ - node: declaredDependencyNode, - message: - `The ${declaredDependencyNode.raw} literal is not a valid dependency ` + - `because it never changes. ` + - `Did you mean to include ${declaredDependencyNode.value} in the array instead?`, - }); + ], + }); + } + // Try to normalize the declared dependency. If we can't then an error + // will be thrown. We will catch that error and report an error. + let declaredDependency; + try { + declaredDependency = analyzePropertyChain( + declaredDependencyNode, + null, + ); + } catch (error: unknown) { + if ( + error instanceof Error && + /Unsupported node type/.test(error.message) + ) { + if (declaredDependencyNode.type === 'Literal') { + if ( + declaredDependencyNode.value && + dependencies.has(declaredDependencyNode.value as string) + ) { + reportProblem({ + node: declaredDependencyNode, + message: + `The ${declaredDependencyNode.raw} literal is not a valid dependency ` + + `because it never changes. ` + + `Did you mean to include ${declaredDependencyNode.value} in the array instead?`, + }); + } else { + reportProblem({ + node: declaredDependencyNode, + message: + `The ${declaredDependencyNode.raw} literal is not a valid dependency ` + + 'because it never changes. You can safely remove it.', + }); + } } else { reportProblem({ node: declaredDependencyNode, message: - `The ${declaredDependencyNode.raw} literal is not a valid dependency ` + - 'because it never changes. You can safely remove it.', + `React Hook ${getSourceCode().getText(reactiveHook)} has a ` + + `complex expression in the dependency array. ` + + 'Extract it to a separate variable so it can be statically checked.', }); } + + return; } else { - reportProblem({ - node: declaredDependencyNode, - message: - `React Hook ${getSource(reactiveHook)} has a ` + - `complex expression in the dependency array. ` + - 'Extract it to a separate variable so it can be statically checked.', - }); + throw error; } - - return; - } else { - throw error; } - } - let maybeID = declaredDependencyNode; - while ( - maybeID.type === 'MemberExpression' || - maybeID.type === 'OptionalMemberExpression' || - maybeID.type === 'ChainExpression' - ) { - maybeID = maybeID.object || maybeID.expression.object; - } - const isDeclaredInComponent = !componentScope.through.some( - ref => ref.identifier === maybeID, - ); + let maybeID = declaredDependencyNode; + while ( + maybeID.type === 'MemberExpression' || + maybeID.type === 'OptionalMemberExpression' || + maybeID.type === 'ChainExpression' + ) { + // @ts-expect-error This can be done better + maybeID = maybeID.object || maybeID.expression.object; + } + const isDeclaredInComponent = !componentScope.through.some( + ref => ref.identifier === maybeID, + ); - // Add the dependency to our declared dependency map. - declaredDependencies.push({ - key: declaredDependency, - node: declaredDependencyNode, - }); + // Add the dependency to our declared dependency map. + declaredDependencies.push({ + key: declaredDependency, + node: declaredDependencyNode, + }); - if (!isDeclaredInComponent) { - externalDependencies.add(declaredDependency); - } - }); + if (!isDeclaredInComponent) { + externalDependencies.add(declaredDependency); + } + }, + ); } const { @@ -824,10 +892,10 @@ export default { const message = `The '${construction.name.name}' ${depType} ${causation} the dependencies of ` + - `${reactiveHookName} Hook (at line ${declaredDependenciesNode.loc.start.line}) ` + + `${reactiveHookName} Hook (at line ${declaredDependenciesNode.loc?.start.line}) ` + `change on every render. ${advice}`; - let suggest; + let suggest: Rule.ReportDescriptor['suggest']; // Only handle the simple case of variable assignments. // Wrapping function declarations can mess up hoisting. if ( @@ -848,12 +916,12 @@ export default { : ['useCallback(', ')']; return [ // TODO: also add an import? - fixer.insertTextBefore(construction.node.init, before), + fixer.insertTextBefore(construction.node.init!, before), // TODO: ideally we'd gather deps here but it would require // restructuring the rule code. This will cause a new lint // error to appear immediately for useCallback. Note we're // not adding [] because would that changes semantics. - fixer.insertTextAfter(construction.node.init, after), + fixer.insertTextAfter(construction.node.init!, after), ]; }, }, @@ -889,7 +957,7 @@ export default { } // Alphabetize the suggestions, but only if deps were already alphabetized. - function areDeclaredDepsAlphabetized() { + function areDeclaredDepsAlphabetized(): boolean { if (declaredDependencies.length === 0) { return true; } @@ -905,7 +973,7 @@ export default { // This function is the last step before printing a dependency, so now is a good time to // check whether any members in our path are always used as optional-only. In that case, // we will use ?. instead of . to concatenate those parts of the path. - function formatDependency(path) { + function formatDependency(path: string): string { const members = path.split('.'); let finalPath = ''; for (let i = 0; i < members.length; i++) { @@ -919,7 +987,12 @@ export default { return finalPath; } - function getWarningMessage(deps, singlePrefix, label, fixVerb) { + function getWarningMessage( + deps: Set, + singlePrefix: string, + label: string, + fixVerb: string, + ): string | null { if (deps.size === 0) { return null; } @@ -942,7 +1015,7 @@ export default { let extraWarning = ''; if (unnecessaryDependencies.size > 0) { - let badRef = null; + let badRef: string | null = null; Array.from(unnecessaryDependencies.keys()).forEach(key => { if (badRef !== null) { return; @@ -956,7 +1029,7 @@ export default { ` Mutable values like '${badRef}' aren't valid dependencies ` + "because mutating them doesn't re-render the component."; } else if (externalDependencies.size > 0) { - const dep = Array.from(externalDependencies)[0]; + const dep = Array.from(externalDependencies)[0]!; // Don't show this warning for things that likely just got moved *inside* the callback // because in that case they're clearly not referring to globals. if (!scope.set.has(dep)) { @@ -980,8 +1053,7 @@ export default { return; } let isPropsOnlyUsedInMembers = true; - for (let i = 0; i < refs.length; i++) { - const ref = refs[i]; + for (const ref of refs) { const id = fastFindReferenceWithParent( componentScope.block, ref.identifier, @@ -1008,14 +1080,14 @@ export default { ` However, 'props' will change when *any* prop changes, so the ` + `preferred fix is to destructure the 'props' object outside of ` + `the ${reactiveHookName} call and refer to those specific props ` + - `inside ${getSource(reactiveHook)}.`; + `inside ${getSourceCode().getText(reactiveHook)}.`; } } if (!extraWarning && missingDependencies.size > 0) { // See if the user is trying to avoid specifying a callable prop. // This usually means they're unaware of useCallback. - let missingCallbackDep = null; + let missingCallbackDep: string | null = null; missingDependencies.forEach(missingDep => { if (missingCallbackDep) { return; @@ -1023,19 +1095,22 @@ export default { // Is this a variable from top scope? const topScopeRef = componentScope.set.get(missingDep); const usedDep = dependencies.get(missingDep); - if (usedDep.references[0].resolved !== topScopeRef) { + if ( + !usedDep?.references || + usedDep?.references[0]?.resolved !== topScopeRef + ) { return; } // Is this a destructured prop? - const def = topScopeRef.defs[0]; + const def = topScopeRef?.defs[0]; if (def == null || def.name == null || def.type !== 'Parameter') { return; } // Was it called in at least one case? Then it's a function. let isFunctionCall = false; - let id; - for (let i = 0; i < usedDep.references.length; i++) { - id = usedDep.references[i].identifier; + let id: Identifier | undefined; + for (const reference of usedDep.references) { + id = reference.identifier; if ( id != null && id.parent != null && @@ -1064,17 +1139,21 @@ export default { } if (!extraWarning && missingDependencies.size > 0) { - let setStateRecommendation = null; - missingDependencies.forEach(missingDep => { + let setStateRecommendation: { + missingDep: string; + setter: string; + form: 'reducer' | 'updater' | 'inlineReducer'; + } | null = null; + for (const missingDep of missingDependencies) { if (setStateRecommendation !== null) { - return; + break; } - const usedDep = dependencies.get(missingDep); + const usedDep = dependencies.get(missingDep)!; const references = usedDep.references; let id; let maybeCall; - for (let i = 0; i < references.length; i++) { - id = references[i].identifier; + for (const reference of references) { + id = reference.identifier; maybeCall = id.parent; // Try to see if we have setState(someExpr(missingDep)). while (maybeCall != null && maybeCall !== componentScope.block) { @@ -1083,22 +1162,27 @@ export default { maybeCall.callee, ); if (correspondingStateVariable != null) { - if (correspondingStateVariable.name === missingDep) { + if ( + 'name' in correspondingStateVariable && + correspondingStateVariable.name === missingDep + ) { // setCount(count + 1) setStateRecommendation = { missingDep, - setter: maybeCall.callee.name, + setter: + 'name' in maybeCall.callee ? maybeCall.callee.name : '', form: 'updater', }; } else if (stateVariables.has(id)) { // setCount(count + increment) setStateRecommendation = { missingDep, - setter: maybeCall.callee.name, + setter: + 'name' in maybeCall.callee ? maybeCall.callee.name : '', form: 'reducer', }; } else { - const resolved = references[i].resolved; + const resolved = reference.resolved; if (resolved != null) { // If it's a parameter *and* a missing dep, // it must be a prop or something inside a prop. @@ -1107,7 +1191,10 @@ export default { if (def != null && def.type === 'Parameter') { setStateRecommendation = { missingDep, - setter: maybeCall.callee.name, + setter: + 'name' in maybeCall.callee + ? maybeCall.callee.name + : '', form: 'inlineReducer', }; } @@ -1122,7 +1209,7 @@ export default { break; } } - }); + } if (setStateRecommendation !== null) { switch (setStateRecommendation.form) { case 'reducer': @@ -1158,7 +1245,7 @@ export default { reportProblem({ node: declaredDependenciesNode, message: - `React Hook ${getSource(reactiveHook)} has ` + + `React Hook ${getSourceCode().getText(reactiveHook)} has ` + // To avoid a long message, show the next actionable item. (getWarningMessage(missingDependencies, 'a', 'missing', 'include') || getWarningMessage( @@ -1191,7 +1278,7 @@ export default { }); } - function visitCallExpression(node) { + function visitCallExpression(node: CallExpression): void { const callbackIndex = getReactiveHookCallbackIndex(node.callee, options); if (callbackIndex === -1) { // Not a React Hook call that needs deps. @@ -1199,7 +1286,9 @@ export default { } let callback = node.arguments[callbackIndex]; const reactiveHook = node.callee; - const reactiveHookName = getNodeWithoutReactNamespace(reactiveHook).name; + const nodeWithoutNamespace = getNodeWithoutReactNamespace(reactiveHook); + const reactiveHookName = + 'name' in nodeWithoutNamespace ? nodeWithoutNamespace.name : ''; const maybeNode = node.arguments[callbackIndex + 1]; const declaredDependenciesNode = maybeNode && @@ -1268,6 +1357,7 @@ export default { // The function passed as a callback is not written inline. // But perhaps it's in the dependencies array? if ( + 'elements' in declaredDependenciesNode && declaredDependenciesNode.elements && declaredDependenciesNode.elements.some( el => el && el.type === 'Identifier' && el.name === callback.name, @@ -1368,7 +1458,7 @@ export default { CallExpression: visitCallExpression, }; }, -}; +} satisfies Rule.RuleModule; // The meat of the logic. function collectRecommendations({ @@ -1377,6 +1467,12 @@ function collectRecommendations({ stableDependencies, externalDependencies, isEffect, +}: { + dependencies: Map; + declaredDependencies: DeclaredDependency[]; + stableDependencies: Set; + externalDependencies: Set; + isEffect: boolean; }) { // Our primary data structure. // It is a logical representation of property chains: @@ -1388,7 +1484,7 @@ function collectRecommendations({ // and the nodes that were *declared* as deps. Then we will // traverse it to learn which deps are missing or unnecessary. const depTree = createDepTree(); - function createDepTree() { + function createDepTree(): DependencyTreeNode { return { isUsed: false, // True if used in code isSatisfiedRecursively: false, // True if specified in deps @@ -1419,7 +1515,10 @@ function collectRecommendations({ }); // Tree manipulation helpers. - function getOrCreateNodeByPath(rootNode, path) { + function getOrCreateNodeByPath( + rootNode: DependencyTreeNode, + path: string, + ): DependencyTreeNode { const keys = path.split('.'); let node = rootNode; for (const key of keys) { @@ -1432,7 +1531,11 @@ function collectRecommendations({ } return node; } - function markAllParentsByPath(rootNode, path, fn) { + function markAllParentsByPath( + rootNode: DependencyTreeNode, + path: string, + fn: (node: DependencyTreeNode) => void, + ): void { const keys = path.split('.'); let node = rootNode; for (const key of keys) { @@ -1446,15 +1549,20 @@ function collectRecommendations({ } // Now we can learn which dependencies are missing or necessary. - const missingDependencies = new Set(); - const satisfyingDependencies = new Set(); + const missingDependencies = new Set(); + const satisfyingDependencies = new Set(); scanTreeRecursively( depTree, missingDependencies, satisfyingDependencies, key => key, ); - function scanTreeRecursively(node, missingPaths, satisfyingPaths, keyToPath) { + function scanTreeRecursively( + node: DependencyTreeNode, + missingPaths: Set, + satisfyingPaths: Set, + keyToPath: (key: string) => string, + ): void { node.children.forEach((child, key) => { const path = keyToPath(key); if (child.isSatisfiedRecursively) { @@ -1484,9 +1592,9 @@ function collectRecommendations({ } // Collect suggestions in the order they were originally specified. - const suggestedDependencies = []; - const unnecessaryDependencies = new Set(); - const duplicateDependencies = new Set(); + const suggestedDependencies: string[] = []; + const unnecessaryDependencies = new Set(); + const duplicateDependencies = new Set(); declaredDependencies.forEach(({key}) => { // Does this declared dep satisfy a real need? if (satisfyingDependencies.has(key)) { @@ -1532,7 +1640,7 @@ function collectRecommendations({ // If the node will result in constructing a referentially unique value, return // its human readable type name, else return null. -function getConstructionExpressionType(node) { +function getConstructionExpressionType(node: Node): string | null { switch (node.type) { case 'ObjectExpression': return 'object'; @@ -1590,6 +1698,11 @@ function scanForConstructions({ declaredDependenciesNode, componentScope, scope, +}: { + declaredDependencies: DeclaredDependency[]; + declaredDependenciesNode: Node; + componentScope: Scope.Scope; + scope: Scope.Scope; }) { const constructions = declaredDependencies .map(({key}) => { @@ -1616,7 +1729,7 @@ function scanForConstructions({ const constantExpressionType = getConstructionExpressionType( node.node.init, ); - if (constantExpressionType != null) { + if (constantExpressionType) { return [ref, constantExpressionType]; } } @@ -1634,12 +1747,11 @@ function scanForConstructions({ } return null; }) - .filter(Boolean); + .filter(Boolean) as [Scope.Variable, string][]; - function isUsedOutsideOfHook(ref) { + function isUsedOutsideOfHook(ref: Scope.Variable): boolean { let foundWriteExpr = false; - for (let i = 0; i < ref.references.length; i++) { - const reference = ref.references[i]; + for (const reference of ref.references) { if (reference.writeExpr) { if (foundWriteExpr) { // Two writes to the same function. @@ -1650,7 +1762,7 @@ function scanForConstructions({ continue; } } - let currentScope = reference.from; + let currentScope: Scope.Scope | null = reference.from; while (currentScope !== scope && currentScope != null) { currentScope = currentScope.upper; } @@ -1666,7 +1778,7 @@ function scanForConstructions({ } return constructions.map(([ref, depType]) => ({ - construction: ref.defs[0], + construction: ref.defs[0] as Scope.Definition, depType, isUsedOutsideOfHook: isUsedOutsideOfHook(ref), })); @@ -1679,11 +1791,13 @@ function scanForConstructions({ * props.foo.(bar) => (props).foo.bar * props.foo.bar.(baz) => (props).foo.bar.baz */ -function getDependency(node) { +function getDependency(node: Node): Node { if ( + node.parent && (node.parent.type === 'MemberExpression' || node.parent.type === 'OptionalMemberExpression') && node.parent.object === node && + 'name' in node.parent.property && node.parent.property.name !== 'current' && !node.parent.computed && !( @@ -1713,9 +1827,13 @@ function getDependency(node) { * It just means there is an optional member somewhere inside. * This particular node might still represent a required member, so check .optional field. */ -function markNode(node, optionalChains, result) { +function markNode( + node: Node, + optionalChains: Map | null, + result: string, +): void { if (optionalChains) { - if (node.optional) { + if ('optional' in node && node.optional) { // We only want to consider it optional if *all* usages were optional. if (!optionalChains.has(result)) { // Mark as (maybe) optional. If there's a required usage, this will be overridden. @@ -1735,7 +1853,10 @@ function markNode(node, optionalChains, result) { * foo.bar(.)baz -> 'foo.bar.baz' * Otherwise throw. */ -function analyzePropertyChain(node, optionalChains) { +function analyzePropertyChain( + node: Node, + optionalChains: Map | null, +): string { if (node.type === 'Identifier' || node.type === 'JSXIdentifier') { const result = node.name; if (optionalChains) { @@ -1755,7 +1876,10 @@ function analyzePropertyChain(node, optionalChains) { const result = `${object}.${property}`; markNode(node, optionalChains, result); return result; - } else if (node.type === 'ChainExpression' && !node.computed) { + } else if ( + node.type === 'ChainExpression' && + (!('computed' in node) || !node.computed) + ) { const expression = node.expression; if (expression.type === 'CallExpression') { @@ -1772,7 +1896,9 @@ function analyzePropertyChain(node, optionalChains) { } } -function getNodeWithoutReactNamespace(node, options) { +function getNodeWithoutReactNamespace( + node: Expression | Super, +): Expression | Identifier | Super { if ( node.type === 'MemberExpression' && node.object.type === 'Identifier' && @@ -1790,7 +1916,13 @@ function getNodeWithoutReactNamespace(node, options) { // 0 for useEffect/useMemo/useCallback(fn). // 1 for useImperativeHandle(ref, fn). // For additionally configured Hooks, assume that they're like useEffect (0). -function getReactiveHookCallbackIndex(calleeNode, options) { +function getReactiveHookCallbackIndex( + calleeNode: Expression | Super, + options?: { + additionalHooks: RegExp | undefined; + enableDangerousAutofixThisMayCauseInfiniteLoops?: boolean; + }, +): 0 | -1 | 1 { const node = getNodeWithoutReactNamespace(calleeNode); if (node.type !== 'Identifier') { return -1; @@ -1812,8 +1944,11 @@ function getReactiveHookCallbackIndex(calleeNode, options) { let name; try { name = analyzePropertyChain(node, null); - } catch (error) { - if (/Unsupported node type/.test(error.message)) { + } catch (error: unknown) { + if ( + error instanceof Error && + /Unsupported node type/.test(error.message) + ) { return 0; } else { throw error; @@ -1836,12 +1971,12 @@ function getReactiveHookCallbackIndex(calleeNode, options) { * - optimized by only searching nodes with a range surrounding our target node * - agnostic to AST node types, it looks for `{ type: string, ... }` */ -function fastFindReferenceWithParent(start, target) { +function fastFindReferenceWithParent(start: Node, target: Node): Node | null { const queue = [start]; - let item = null; + let item: Node; while (queue.length) { - item = queue.shift(); + item = queue.shift() as Node; if (isSameIdentifier(item, target)) { return item; @@ -1872,7 +2007,7 @@ function fastFindReferenceWithParent(start, target) { return null; } -function joinEnglish(arr) { +function joinEnglish(arr: string[]): string { let s = ''; for (let i = 0; i < arr.length; i++) { s += arr[i]; @@ -1887,39 +2022,49 @@ function joinEnglish(arr) { return s; } -function isNodeLike(val) { +function isNodeLike(val: unknown): boolean { return ( typeof val === 'object' && val !== null && !Array.isArray(val) && + 'type' in val && typeof val.type === 'string' ); } -function isSameIdentifier(a, b) { +function isSameIdentifier(a: Node, b: Node): boolean { return ( (a.type === 'Identifier' || a.type === 'JSXIdentifier') && a.type === b.type && a.name === b.name && + !!a.range && + !!b.range && a.range[0] === b.range[0] && a.range[1] === b.range[1] ); } -function isAncestorNodeOf(a, b) { - return a.range[0] <= b.range[0] && a.range[1] >= b.range[1]; +function isAncestorNodeOf(a: Node, b: Node): boolean { + return ( + !!a.range && + !!b.range && + a.range[0] <= b.range[0] && + a.range[1] >= b.range[1] + ); } -function isUseEffectEventIdentifier(node) { +function isUseEffectEventIdentifier(node: Node): boolean { if (__EXPERIMENTAL__) { return node.type === 'Identifier' && node.name === 'useEffectEvent'; } return false; } -function getUnknownDependenciesMessage(reactiveHookName) { +function getUnknownDependenciesMessage(reactiveHookName: string): string { return ( `React Hook ${reactiveHookName} received a function whose dependencies ` + `are unknown. Pass an inline function instead.` ); } + +export default rule; diff --git a/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js b/packages/eslint-plugin-react-hooks/src/RulesOfHooks.ts similarity index 85% rename from packages/eslint-plugin-react-hooks/src/RulesOfHooks.js rename to packages/eslint-plugin-react-hooks/src/RulesOfHooks.ts index fc340519e2..24870d7161 100644 --- a/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js +++ b/packages/eslint-plugin-react-hooks/src/RulesOfHooks.ts @@ -4,18 +4,16 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ - -/* global BigInt */ /* eslint-disable no-for-of-loops/no-for-of-loops */ -'use strict'; +import type {Rule, Scope} from 'eslint'; +import type {CallExpression, DoWhileStatement, Node} from 'estree'; /** * Catch all identifiers that begin with "use" followed by an uppercase Latin * character to exclude identifiers like "user". */ - -function isHookName(s) { +function isHookName(s: string): boolean { return s === 'use' || /^use[A-Z0-9]/.test(s); } @@ -23,8 +21,7 @@ function isHookName(s) { * We consider hooks to be a hook name identifier or a member expression * containing a hook name. */ - -function isHook(node) { +function isHook(node: Node): boolean { if (node.type === 'Identifier') { return isHookName(node.name); } else if ( @@ -44,16 +41,17 @@ function isHook(node) { * Checks if the node is a React component name. React component names must * always start with an uppercase letter. */ - -function isComponentName(node) { +function isComponentName(node: Node): boolean { return node.type === 'Identifier' && /^[A-Z]/.test(node.name); } -function isReactFunction(node, functionName) { +function isReactFunction(node: Node, functionName: string): boolean { return ( - node.name === functionName || + ('name' in node && node.name === functionName) || (node.type === 'MemberExpression' && + 'name' in node.object && node.object.name === 'React' && + 'name' in node.property && node.property.name === functionName) ); } @@ -62,10 +60,10 @@ function isReactFunction(node, functionName) { * Checks if the node is a callback argument of forwardRef. This render function * should follow the rules of hooks. */ - -function isForwardRefCallback(node) { +function isForwardRefCallback(node: Node): boolean { return !!( node.parent && + 'callee' in node.parent && node.parent.callee && isReactFunction(node.parent.callee, 'forwardRef') ); @@ -75,16 +73,16 @@ function isForwardRefCallback(node) { * Checks if the node is a callback argument of React.memo. This anonymous * functional component should follow the rules of hooks. */ - -function isMemoCallback(node) { +function isMemoCallback(node: Node): boolean { return !!( node.parent && + 'callee' in node.parent && node.parent.callee && isReactFunction(node.parent.callee, 'memo') ); } -function isInsideComponentOrHook(node) { +function isInsideComponentOrHook(node: Node | undefined): boolean { while (node) { const functionName = getFunctionName(node); if (functionName) { @@ -100,7 +98,7 @@ function isInsideComponentOrHook(node) { return false; } -function isInsideDoWhileLoop(node) { +function isInsideDoWhileLoop(node: Node | undefined): node is DoWhileStatement { while (node) { if (node.type === 'DoWhileStatement') { return true; @@ -110,18 +108,18 @@ function isInsideDoWhileLoop(node) { return false; } -function isUseEffectEventIdentifier(node) { +function isUseEffectEventIdentifier(node: Node): boolean { if (__EXPERIMENTAL__) { return node.type === 'Identifier' && node.name === 'useEffectEvent'; } return false; } -function isUseIdentifier(node) { +function isUseIdentifier(node: Node): boolean { return isReactFunction(node, 'use'); } -export default { +const rule = { meta: { type: 'problem', docs: { @@ -130,25 +128,28 @@ export default { url: 'https://reactjs.org/docs/hooks-rules.html', }, }, - create(context) { - let lastEffect = null; - const codePathReactHooksMapStack = []; - const codePathSegmentStack = []; + create(context: Rule.RuleContext) { + let lastEffect: CallExpression | null = null; + const codePathReactHooksMapStack: Map[] = []; + const codePathSegmentStack: Rule.CodePathSegment[] = []; const useEffectEventFunctions = new WeakSet(); // For a given scope, iterate through the references and add all useEffectEvent definitions. We can // do this in non-Program nodes because we can rely on the assumption that useEffectEvent functions // can only be declared within a component or hook at its top level. - function recordAllUseEffectEventFunctions(scope) { + function recordAllUseEffectEventFunctions(scope: Scope.Scope): void { for (const reference of scope.references) { const parent = reference.identifier.parent; if ( - parent.type === 'VariableDeclarator' && + parent?.type === 'VariableDeclarator' && parent.init && parent.init.type === 'CallExpression' && parent.init.callee && isUseEffectEventIdentifier(parent.init.callee) ) { + if (reference.resolved === null) { + throw new Error('Unexpected null reference.resolved'); + } for (const ref of reference.resolved.references) { if (ref !== reference) { useEffectEventFunctions.add(ref.identifier); @@ -159,26 +160,26 @@ export default { } /** - * SourceCode#getText that also works down to ESLint 3.0.0 + * SourceCode that also works down to ESLint 3.0.0 */ - const getSource = - typeof context.getSource === 'function' - ? node => { - return context.getSource(node); + const getSourceCode = + typeof context.getSourceCode === 'function' + ? () => { + return context.getSourceCode(); } - : node => { - return context.sourceCode.getText(node); + : () => { + return context.sourceCode; }; /** * SourceCode#getScope that also works down to ESLint 3.0.0 */ const getScope = typeof context.getScope === 'function' - ? () => { + ? (): Scope.Scope => { return context.getScope(); } - : node => { - return context.sourceCode.getScope(node); + : (node: Node): Scope.Scope => { + return getSourceCode().getScope(node); }; return { @@ -187,7 +188,10 @@ export default { onCodePathSegmentEnd: () => codePathSegmentStack.pop(), // Maintain code path stack as we traverse. - onCodePathStart: () => codePathReactHooksMapStack.push(new Map()), + onCodePathStart: () => + codePathReactHooksMapStack.push( + new Map(), + ), // Process our code path. // @@ -195,8 +199,10 @@ export default { // segment and reachable from every final segment. onCodePathEnd(codePath, codePathNode) { const reactHooksMap = codePathReactHooksMapStack.pop(); - if (reactHooksMap.size === 0) { + if (reactHooksMap?.size === 0) { return; + } else if (typeof reactHooksMap === 'undefined') { + throw new Error('Unexpected undefined reactHooksMap'); } // All of the segments which are cyclic are recorded in this set. @@ -223,11 +229,13 @@ export default { * * Populates `cyclic` with cyclic segments. */ - - function countPathsFromStart(segment, pathHistory) { + function countPathsFromStart( + segment: Rule.CodePathSegment, + pathHistory?: Set, + ): bigint { const {cache} = countPathsFromStart; let paths = cache.get(segment.id); - const pathList = new Set(pathHistory); + const pathList = new Set(pathHistory); // If `pathList` includes the current segment then we've found a cycle! // We need to fill `cyclic` with all segments inside cycle @@ -295,7 +303,10 @@ export default { * Populates `cyclic` with cyclic segments. */ - function countPathsToEnd(segment, pathHistory) { + function countPathsToEnd( + segment: Rule.CodePathSegment, + pathHistory?: Set, + ): bigint { const {cache} = countPathsToEnd; let paths = cache.get(segment.id); const pathList = new Set(pathHistory); @@ -359,7 +370,9 @@ export default { * so we would return that. */ - function shortestPathLengthToStart(segment) { + function shortestPathLengthToStart( + segment: Rule.CodePathSegment, + ): number { const {cache} = shortestPathLengthToStart; let length = cache.get(segment.id); @@ -392,9 +405,9 @@ export default { return length; } - countPathsFromStart.cache = new Map(); - countPathsToEnd.cache = new Map(); - shortestPathLengthToStart.cache = new Map(); + countPathsFromStart.cache = new Map(); + countPathsToEnd.cache = new Map(); + shortestPathLengthToStart.cache = new Map(); // Count all code paths to the end of our component/hook. Also primes // the `countPathsToEnd` cache. @@ -502,7 +515,7 @@ export default { context.report({ node: hook, message: - `React Hook "${getSource(hook)}" may be executed ` + + `React Hook "${getSourceCode().getText(hook)}" may be executed ` + 'more than once. Possibly because it is called in a loop. ' + 'React Hooks must be called in the exact same order in ' + 'every component render.', @@ -516,12 +529,13 @@ export default { // called in. if (isDirectlyInsideComponentOrHook) { // Report an error if the hook is called inside an async function. + // @ts-expect-error the above check hasn't properly type-narrowed `codePathNode` (async doesn't exist on Node) const isAsyncFunction = codePathNode.async; if (isAsyncFunction) { context.report({ node: hook, message: - `React Hook "${getSource(hook)}" cannot be ` + + `React Hook "${getSourceCode().getText(hook)}" cannot be ` + 'called in an async function.', }); } @@ -537,7 +551,7 @@ export default { !isInsideDoWhileLoop(hook) // wrapping do/while loops are checked separately. ) { const message = - `React Hook "${getSource(hook)}" is called ` + + `React Hook "${getSourceCode().getText(hook)}" is called ` + 'conditionally. React Hooks must be called in the exact ' + 'same order in every component render.' + (possiblyHasEarlyReturn @@ -549,21 +563,22 @@ export default { } else if ( codePathNode.parent && (codePathNode.parent.type === 'MethodDefinition' || + // @ts-expect-error `ClassProperty` was removed from typescript-estree in https://github.com/typescript-eslint/typescript-eslint/pull/3806 codePathNode.parent.type === 'ClassProperty' || codePathNode.parent.type === 'PropertyDefinition') && codePathNode.parent.value === codePathNode ) { // Custom message for hooks inside a class const message = - `React Hook "${getSource(hook)}" cannot be called ` + + `React Hook "${getSourceCode().getText(hook)}" cannot be called ` + 'in a class component. React Hooks must be called in a ' + 'React function component or a custom React Hook function.'; context.report({node: hook, message}); } else if (codePathFunctionName) { // Custom message if we found an invalid function name. const message = - `React Hook "${getSource(hook)}" is called in ` + - `function "${getSource(codePathFunctionName)}" ` + + `React Hook "${getSourceCode().getText(hook)}" is called in ` + + `function "${getSourceCode().getText(codePathFunctionName)}" ` + 'that is neither a React function component nor a custom ' + 'React Hook function.' + ' React component names must start with an uppercase letter.' + @@ -572,7 +587,7 @@ export default { } else if (codePathNode.type === 'Program') { // These are dangerous if you have inline requires enabled. const message = - `React Hook "${getSource(hook)}" cannot be called ` + + `React Hook "${getSourceCode().getText(hook)}" cannot be called ` + 'at the top level. React Hooks must be called in a ' + 'React function component or a custom React Hook function.'; context.report({node: hook, message}); @@ -585,7 +600,7 @@ export default { // `use(...)` can be called in callbacks. if (isSomewhereInsideComponentOrHook && !isUseIdentifier(hook)) { const message = - `React Hook "${getSource(hook)}" cannot be called ` + + `React Hook "${getSourceCode().getText(hook)}" cannot be called ` + 'inside a callback. React Hooks must be called in a ' + 'React function component or a custom React Hook function.'; context.report({node: hook, message}); @@ -638,7 +653,7 @@ export default { context.report({ node, message: - `\`${getSource( + `\`${getSourceCode().getText( node, )}\` is a function created with React Hook "useEffectEvent", and can only be called from ` + 'the same component. They cannot be assigned to variables or passed down.', @@ -667,7 +682,7 @@ export default { }, }; }, -}; +} satisfies Rule.RuleModule; /** * Gets the static name of a function AST node. For function declarations it is @@ -677,7 +692,7 @@ export default { * same AST nodes with some exceptions to better fit our use case. */ -function getFunctionName(node) { +function getFunctionName(node: Node) { if ( node.type === 'FunctionDeclaration' || (node.type === 'FunctionExpression' && node.id) @@ -693,20 +708,20 @@ function getFunctionName(node) { node.type === 'ArrowFunctionExpression' ) { if ( - node.parent.type === 'VariableDeclarator' && + node.parent?.type === 'VariableDeclarator' && node.parent.init === node ) { // const useHook = () => {}; return node.parent.id; } else if ( - node.parent.type === 'AssignmentExpression' && + node.parent?.type === 'AssignmentExpression' && node.parent.right === node && node.parent.operator === '=' ) { // useHook = () => {}; return node.parent.left; } else if ( - node.parent.type === 'Property' && + node.parent?.type === 'Property' && node.parent.value === node && !node.parent.computed ) { @@ -721,8 +736,9 @@ function getFunctionName(node) { // class {useHook = () => {}} // class {useHook() {}} } else if ( - node.parent.type === 'AssignmentPattern' && + node.parent?.type === 'AssignmentPattern' && node.parent.right === node && + // @ts-expect-error Property computed does not exist on type `AssignmentPattern`. !node.parent.computed ) { // const {useHook = () => {}} = {}; @@ -742,7 +758,8 @@ function getFunctionName(node) { /** * Convenience function for peeking the last item in a stack. */ - -function last(array) { - return array[array.length - 1]; +function last(array: T[]): T { + return array[array.length - 1] as T; } + +export default rule; diff --git a/packages/eslint-plugin-react-hooks/src/index.js b/packages/eslint-plugin-react-hooks/src/index.js deleted file mode 100644 index 0ebfbc91a5..0000000000 --- a/packages/eslint-plugin-react-hooks/src/index.js +++ /dev/null @@ -1,61 +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. - */ - -'use strict'; - -import RulesOfHooks from './RulesOfHooks'; -import ExhaustiveDeps from './ExhaustiveDeps'; - -// All rules -export const rules = { - 'rules-of-hooks': RulesOfHooks, - 'exhaustive-deps': ExhaustiveDeps, -}; - -// Config rules -const configRules = { - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'warn', -}; - -// Legacy config -const legacyRecommendedConfig = { - plugins: ['react-hooks'], - rules: configRules, -}; - -// Base plugin object -const reactHooksPlugin = { - meta: {name: 'eslint-plugin-react-hooks'}, - rules, -}; - -// Flat config -const flatRecommendedConfig = { - name: 'react-hooks/recommended', - plugins: {'react-hooks': reactHooksPlugin}, - rules: configRules, -}; - -export const configs = { - /** Legacy recommended config, to be used with rc-based configurations */ - 'recommended-legacy': legacyRecommendedConfig, - - /** Latest recommended config, to be used with flat configurations */ - 'recommended-latest': flatRecommendedConfig, - - /** - * 'recommended' is currently aliased to the legacy / rc recommended config) to maintain backwards compatibility. - * This is deprecated and in v6, it will switch to alias the flat recommended config. - */ - recommended: legacyRecommendedConfig, -}; - -export default { - ...reactHooksPlugin, - configs, -}; diff --git a/packages/eslint-plugin-react-hooks/src/index.ts b/packages/eslint-plugin-react-hooks/src/index.ts new file mode 100644 index 0000000000..42b55320fc --- /dev/null +++ b/packages/eslint-plugin-react-hooks/src/index.ts @@ -0,0 +1,64 @@ +/** + * 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 RulesOfHooks from './RulesOfHooks'; +import ExhaustiveDeps from './ExhaustiveDeps'; +import type {ESLint, Linter, Rule} from 'eslint'; + +// All rules +const rules = { + 'rules-of-hooks': RulesOfHooks, + 'exhaustive-deps': ExhaustiveDeps, +} satisfies Record; + +// Config rules +const configRules = { + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', +} satisfies Linter.RulesRecord; + +// Legacy config +const legacyRecommendedConfig = { + plugins: ['react-hooks'], + rules: configRules, +} satisfies Linter.LegacyConfig; + +// Plugin object +const plugin = { + // TODO: Make this more dynamic to populate version from package.json. + // This can be done by injecting at build time, since importing the package.json isn't an option in Meta + meta: {name: 'eslint-plugin-react-hooks'}, + rules, + configs: { + /** Legacy recommended config, to be used with rc-based configurations */ + 'recommended-legacy': legacyRecommendedConfig, + + /** + * 'recommended' is currently aliased to the legacy / rc recommended config) to maintain backwards compatibility. + * This is deprecated and in v6, it will switch to alias the flat recommended config. + */ + recommended: legacyRecommendedConfig, + + /** Latest recommended config, to be used with flat configurations */ + 'recommended-latest': { + name: 'react-hooks/recommended', + plugins: { + get 'react-hooks'(): ESLint.Plugin { + return plugin; + }, + }, + rules: configRules, + }, + }, +} satisfies ESLint.Plugin; + +const configs = plugin.configs; +const meta = plugin.meta; +export {configs, meta, rules}; + +// TODO: If the plugin is ever updated to be pure ESM and drops support for rc-based configs, then it should be exporting the plugin as default +// instead of individual named exports. +// export default plugin; diff --git a/packages/eslint-plugin-react-hooks/src/types/estree.d.ts b/packages/eslint-plugin-react-hooks/src/types/estree.d.ts index 10337ef7d6..f266369704 100644 --- a/packages/eslint-plugin-react-hooks/src/types/estree.d.ts +++ b/packages/eslint-plugin-react-hooks/src/types/estree.d.ts @@ -1,3 +1,5 @@ +import {Expression, Identifier, Node} from 'estree-jsx'; + /** * This file augments the `estree` types to include types that are not built-in to `estree` or `estree-jsx`. * This is necessary because the `estree` types are used by ESLint, and ESLint does not natively support diff --git a/packages/eslint-plugin-react-hooks/tsconfig.json b/packages/eslint-plugin-react-hooks/tsconfig.json index db8a489364..e67b840d3f 100644 --- a/packages/eslint-plugin-react-hooks/tsconfig.json +++ b/packages/eslint-plugin-react-hooks/tsconfig.json @@ -6,7 +6,6 @@ "moduleResolution": "Bundler", "lib": ["ES2020"], "rootDir": ".", - "noEmit": true, "sourceMap": false, "types": ["estree-jsx", "node"] }, diff --git a/packages/eslint-plugin-react-hooks/tsup.config.ts b/packages/eslint-plugin-react-hooks/tsup.config.ts deleted file mode 100644 index e275d0495e..0000000000 --- a/packages/eslint-plugin-react-hooks/tsup.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {defineConfig} from 'tsup'; - -export default defineConfig({ - clean: true, - dts: true, - entry: ['src/index.ts'], - format: ['cjs'], - outDir: 'build', -}); diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index c66cff82c5..0a378c4f31 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -1184,17 +1184,19 @@ const bundles = [ /******* ESLint Plugin for Hooks *******/ { - // TODO: it's awkward to create a bundle for this but if we don't, the package - // won't get copied. We also can't create just DEV bundle because it contains a - // NODE_ENV check inside. We should probably tweak our build process to allow - // "raw" packages that don't get bundled. - bundleTypes: [NODE_DEV, NODE_PROD], + // TODO: we're building this from typescript source now, but there's really + // no reason to have both dev and prod for this package. It's + // currently required in order for the package to be copied over correctly. + // So, it would be worth improving that flow. + name: 'eslint-plugin-react-hooks', + bundleTypes: [NODE_DEV, NODE_PROD, CJS_DTS], moduleType: ISOMORPHIC, - entry: 'eslint-plugin-react-hooks', + entry: 'eslint-plugin-react-hooks/src/index.ts', global: 'ESLintPluginReactHooks', minifyWithProdErrorCodes: false, wrapWithModuleBoundaries: false, externals: [], + tsconfig: './packages/eslint-plugin-react-hooks/tsconfig.json', }, /******* React Fresh *******/ diff --git a/yarn.lock b/yarn.lock index 44d5906251..ba71ba7abe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2403,131 +2403,6 @@ opn "5.3.0" react "^16.13.1" -"@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" @@ -2924,15 +2799,6 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/gen-mapping@^0.3.2": - version "0.3.8" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" - integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" @@ -3396,101 +3262,6 @@ estree-walker "^2.0.2" picomatch "^4.0.2" -"@rollup/rollup-android-arm-eabi@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.7.tgz#e554185b1afa5509a7a4040d15ec0c3b4435ded1" - integrity sha512-l6CtzHYo8D2TQ3J7qJNpp3Q1Iye56ssIAtqbM2H8axxCEEwvN7o8Ze9PuIapbxFL3OHrJU2JBX6FIIVnP/rYyw== - -"@rollup/rollup-android-arm64@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.7.tgz#b1ee64bb413b2feba39803b0a1bebf2a9f3d70e1" - integrity sha512-KvyJpFUueUnSp53zhAa293QBYqwm94TgYTIfXyOTtidhm5V0LbLCJQRGkQClYiX3FXDQGSvPxOTD/6rPStMMDg== - -"@rollup/rollup-darwin-arm64@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.7.tgz#bfdce3e07a345dd1bd628f3b796050f39629d7f0" - integrity sha512-jq87CjmgL9YIKvs8ybtIC98s/M3HdbqXhllcy9EdLV0yMg1DpxES2gr65nNy7ObNo/vZ/MrOTxt0bE5LinL6mA== - -"@rollup/rollup-darwin-x64@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.7.tgz#781a94a537c57bdf0a500e47a25ab5985e5e8dff" - integrity sha512-rSI/m8OxBjsdnMMg0WEetu/w+LhLAcCDEiL66lmMX4R3oaml3eXz3Dxfvrxs1FbzPbJMaItQiksyMfv1hoIxnA== - -"@rollup/rollup-freebsd-arm64@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.7.tgz#7a028357cbd12c5869c446ad18177c89f3405102" - integrity sha512-oIoJRy3ZrdsXpFuWDtzsOOa/E/RbRWXVokpVrNnkS7npz8GEG++E1gYbzhYxhxHbO2om1T26BZjVmdIoyN2WtA== - -"@rollup/rollup-freebsd-x64@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.7.tgz#f24836a6371cccc4408db74f0fd986dacf098950" - integrity sha512-X++QSLm4NZfZ3VXGVwyHdRf58IBbCu9ammgJxuWZYLX0du6kZvdNqPwrjvDfwmi6wFdvfZ/s6K7ia0E5kI7m8Q== - -"@rollup/rollup-linux-arm-gnueabihf@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.7.tgz#95f27e96f0eb9b9ae9887739a8b6dffc90c1237f" - integrity sha512-Z0TzhrsNqukTz3ISzrvyshQpFnFRfLunYiXxlCRvcrb3nvC5rVKI+ZXPFG/Aa4jhQa1gHgH3A0exHaRRN4VmdQ== - -"@rollup/rollup-linux-arm-musleabihf@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.7.tgz#677b34fba9d070877736c3fe8b02aacb5e142d97" - integrity sha512-nkznpyXekFAbvFBKBy4nNppSgneB1wwG1yx/hujN3wRnhnkrYVugMTCBXED4+Ni6thoWfQuHNYbFjgGH0MBXtw== - -"@rollup/rollup-linux-arm64-gnu@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.7.tgz#32d3d19dedde54e91574a098f22ea43a09cf63dd" - integrity sha512-KCjlUkcKs6PjOcxolqrXglBDcfCuUCTVlX5BgzgoJHw+1rWH1MCkETLkLe5iLLS9dP5gKC7mp3y6x8c1oGBUtA== - -"@rollup/rollup-linux-arm64-musl@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.7.tgz#a58dff44a18696df65ed8c0ad68a2945cf900484" - integrity sha512-uFLJFz6+utmpbR313TTx+NpPuAXbPz4BhTQzgaP0tozlLnGnQ6rCo6tLwaSa6b7l6gRErjLicXQ1iPiXzYotjw== - -"@rollup/rollup-linux-loongarch64-gnu@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.7.tgz#a7488ab078233111e8aeb370d1ecf107ec7e1716" - integrity sha512-ws8pc68UcJJqCpneDFepnwlsMUFoWvPbWXT/XUrJ7rWUL9vLoIN3GAasgG+nCvq8xrE3pIrd+qLX/jotcLy0Qw== - -"@rollup/rollup-linux-powerpc64le-gnu@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.7.tgz#e9b9c0d6bd248a92b2d6ec01ebf99c62ae1f2e9a" - integrity sha512-vrDk9JDa/BFkxcS2PbWpr0C/LiiSLxFbNOBgfbW6P8TBe9PPHx9Wqbvx2xgNi1TOAyQHQJ7RZFqBiEohm79r0w== - -"@rollup/rollup-linux-riscv64-gnu@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.7.tgz#0df84ce2bea48ee686fb55060d76ab47aff45c4c" - integrity sha512-rB+ejFyjtmSo+g/a4eovDD1lHWHVqizN8P0Hm0RElkINpS0XOdpaXloqM4FBkF9ZWEzg6bezymbpLmeMldfLTw== - -"@rollup/rollup-linux-s390x-gnu@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.7.tgz#73df374c57d036856e33dbd2715138922e91e452" - integrity sha512-nNXNjo4As6dNqRn7OrsnHzwTgtypfRA3u3AKr0B3sOOo+HkedIbn8ZtFnB+4XyKJojIfqDKmbIzO1QydQ8c+Pw== - -"@rollup/rollup-linux-x64-gnu@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.7.tgz#f27af0b55f0cdd84e182e6cd44a6d03da0458149" - integrity sha512-9kPVf9ahnpOMSGlCxXGv980wXD0zRR3wyk8+33/MXQIpQEOpaNe7dEHm5LMfyRZRNt9lMEQuH0jUKj15MkM7QA== - -"@rollup/rollup-linux-x64-musl@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.7.tgz#c7981ad5cfb8c3cd5d643d33ca54e4d2802b9201" - integrity sha512-7wJPXRWTTPtTFDFezA8sle/1sdgxDjuMoRXEKtx97ViRxGGkVQYovem+Q8Pr/2HxiHp74SSRG+o6R0Yq0shPwQ== - -"@rollup/rollup-win32-arm64-msvc@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.7.tgz#06cedc0ef3cbf1cbd8abcf587090712e40ae6941" - integrity sha512-MN7aaBC7mAjsiMEZcsJvwNsQVNZShgES/9SzWp1HC9Yjqb5OpexYnRjF7RmE4itbeesHMYYQiAtUAQaSKs2Rfw== - -"@rollup/rollup-win32-ia32-msvc@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.7.tgz#90b39b977b14961a769be6ea61238e7fc668dd4d" - integrity sha512-aeawEKYswsFu1LhDM9RIgToobquzdtSc4jSVqHV8uApz4FVvhFl/mKh92wc8WpFc6aYCothV/03UjY6y7yLgbg== - -"@rollup/rollup-win32-x64-msvc@4.34.7": - version "4.34.7" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.7.tgz#6531d61e7141091eaab0461ee8e0380c10e4ca57" - integrity sha512-4ZedScpxxIrVO7otcZ8kCX1mZArtH2Wfj3uFCxRJ9NO80gg1XV0U/b2f/MKaGwj2X3QopHfoWiDQ917FRpwY3w== - "@sinclair/typebox@^0.25.16": version "0.25.24" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" @@ -3680,7 +3451,7 @@ dependencies: "@types/estree" "*" -"@types/estree@*", "@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.6": +"@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.6": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== @@ -5760,13 +5531,6 @@ bundle-name@^3.0.0: dependencies: run-applescript "^5.0.0" -bundle-require@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-5.1.0.tgz#8db66f41950da3d77af1ef3322f4c3e04009faee" - integrity sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA== - dependencies: - load-tsconfig "^0.2.3" - bunyan@1.8.15: version "1.8.15" resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.15.tgz#8ce34ca908a17d0776576ca1b2f6cbd916e93b46" @@ -5787,11 +5551,6 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -cac@^6.7.14: - version "6.7.14" - resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" - integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== - cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -6093,13 +5852,6 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" -chokidar@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" - integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== - dependencies: - readdirp "^4.0.1" - chownr@^1.0.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -6368,7 +6120,7 @@ commander@^2.18.0, commander@^2.20.0, commander@^2.6.0, commander@^2.8.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^4.0.0, commander@^4.0.1: +commander@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== @@ -6511,11 +6263,6 @@ connect-history-api-fallback@^2.0.0: resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== -consola@^3.2.3: - version "3.4.0" - resolved "https://registry.yarnpkg.com/consola/-/consola-3.4.0.tgz#4cfc9348fd85ed16a17940b3032765e31061ab88" - integrity sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA== - console-browserify@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" @@ -7039,13 +6786,6 @@ debug@^4.3.4, debug@~4.3.1: dependencies: ms "2.1.2" -debug@^4.3.7: - version "4.4.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" - integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== - dependencies: - ms "^2.1.3" - decamelize@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-6.0.0.tgz#8cad4d916fde5c41a264a43d0ecc56fe3d31749e" @@ -7744,37 +7484,6 @@ es6-error@4.1.1, es6-error@^4.1.1: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -esbuild@^0.24.0: - 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.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.0.2.tgz#6a580d70edb87880f22b4c91d0d56078df6962c4" @@ -8649,11 +8358,6 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -fdir@^6.4.2: - version "6.4.3" - resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.3.tgz#011cdacf837eca9b811c89dbb902df714273db72" - integrity sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw== - fetch-blob@^3.1.2, fetch-blob@^3.1.4: version "3.2.0" resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" @@ -9292,18 +8996,6 @@ glob@^10.2.5: minipass "^5.0.0 || ^6.0.2" path-scurry "^1.7.0" -glob@^10.3.10: - version "10.4.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== - dependencies: - foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" - minipass "^7.1.2" - package-json-from-dist "^1.0.0" - path-scurry "^1.11.1" - glob@^6.0.1: version "6.0.4" resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" @@ -11489,11 +11181,6 @@ jose@5.4.1: resolved "https://registry.yarnpkg.com/jose/-/jose-5.4.1.tgz#b471ee3963920ba5452fd1b1398c8ba72a7b2fcf" integrity sha512-U6QajmpV/nhL9SyfAewo000fkiRQ+Yd2H0lBxJJ9apjpOgkOcBQJWOrMo917lxLptdS/n/o/xPzMkXhF46K8hQ== -joycon@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" - integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== - jpeg-js@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa" @@ -11880,11 +11567,6 @@ lighthouse-logger@^1.0.0: debug "^2.6.8" marky "^1.2.0" -lilconfig@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" - integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== - lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -11906,11 +11588,6 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -load-tsconfig@^0.2.3: - version "0.2.5" - resolved "https://registry.yarnpkg.com/load-tsconfig/-/load-tsconfig-0.2.5.tgz#453b8cd8961bfb912dea77eb6c168fe8cca3d3a1" - integrity sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg== - loader-runner@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" @@ -12047,11 +11724,6 @@ lodash.omitby@4.6.0: resolved "https://registry.yarnpkg.com/lodash.omitby/-/lodash.omitby-4.6.0.tgz#5c15ff4754ad555016b53c041311e8f079204791" integrity sha1-XBX/R1StVVAWtTwEExHo8HkgR5E= -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== - lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" @@ -12572,7 +12244,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1, ms@^2.1.2, ms@^2.1.3: +ms@2.1.3, ms@^2.1.1, ms@^2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -12604,7 +12276,7 @@ mv@~2: ncp "~2.0.0" rimraf "~2.4.0" -mz@2.7.0, mz@^2.7.0: +mz@2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== @@ -13646,11 +13318,6 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picocolors@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" - integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== - picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -13821,13 +13488,6 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= -postcss-load-config@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz#6fd7dcd8ae89badcf1b2d644489cbabf83aa8096" - integrity sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g== - dependencies: - lilconfig "^3.1.1" - postcss-modules-extract-imports@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz#dc87e34148ec7eab5f791f7cd5849833375b741a" @@ -14556,11 +14216,6 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" -readdirp@^4.0.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" - integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== - readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -15003,34 +14658,6 @@ rollup@^3.29.5: optionalDependencies: fsevents "~2.3.2" -rollup@^4.24.0: - version "4.34.7" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.34.7.tgz#e00d8550688a616a3481c6446bb688d4c753ba8f" - integrity sha512-8qhyN0oZ4x0H6wmBgfKxJtxM7qS98YJ0k0kNh5ECVtuchIJ7z9IVVvzpmtQyT10PXKMtBxYr1wQ5Apg8RS8kXQ== - dependencies: - "@types/estree" "1.0.6" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.34.7" - "@rollup/rollup-android-arm64" "4.34.7" - "@rollup/rollup-darwin-arm64" "4.34.7" - "@rollup/rollup-darwin-x64" "4.34.7" - "@rollup/rollup-freebsd-arm64" "4.34.7" - "@rollup/rollup-freebsd-x64" "4.34.7" - "@rollup/rollup-linux-arm-gnueabihf" "4.34.7" - "@rollup/rollup-linux-arm-musleabihf" "4.34.7" - "@rollup/rollup-linux-arm64-gnu" "4.34.7" - "@rollup/rollup-linux-arm64-musl" "4.34.7" - "@rollup/rollup-linux-loongarch64-gnu" "4.34.7" - "@rollup/rollup-linux-powerpc64le-gnu" "4.34.7" - "@rollup/rollup-linux-riscv64-gnu" "4.34.7" - "@rollup/rollup-linux-s390x-gnu" "4.34.7" - "@rollup/rollup-linux-x64-gnu" "4.34.7" - "@rollup/rollup-linux-x64-musl" "4.34.7" - "@rollup/rollup-win32-arm64-msvc" "4.34.7" - "@rollup/rollup-win32-ia32-msvc" "4.34.7" - "@rollup/rollup-win32-x64-msvc" "4.34.7" - 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" @@ -15671,13 +15298,6 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@0.8.0-beta.0: - version "0.8.0-beta.0" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" - integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== - dependencies: - whatwg-url "^7.0.0" - source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -16136,19 +15756,6 @@ style-loader@^1.2.1: loader-utils "^2.0.0" schema-utils "^2.6.6" -sucrase@^3.35.0: - version "3.35.0" - resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" - integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== - dependencies: - "@jridgewell/gen-mapping" "^0.3.2" - commander "^4.0.0" - glob "^10.3.10" - lines-and-columns "^1.1.6" - mz "^2.7.0" - pirates "^4.0.1" - ts-interface-checker "^0.1.9" - sumchecker@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42" @@ -16437,19 +16044,6 @@ tiny-warning@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== -tinyexec@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" - integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== - -tinyglobby@^0.2.9: - version "0.2.10" - resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.10.tgz#e712cf2dc9b95a1f5c5bbd159720e15833977a0f" - integrity sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew== - dependencies: - fdir "^6.4.2" - picomatch "^4.0.2" - titleize@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53" @@ -16556,13 +16150,6 @@ tough-cookie@^4.1.2: universalify "^0.2.0" url-parse "^1.5.3" -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA== - dependencies: - punycode "^2.1.0" - tr46@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-4.1.1.tgz#281a758dcc82aeb4fe38c7dfe4d11a395aac8469" @@ -16580,11 +16167,6 @@ traverse-chain@~0.1.0: resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1" integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE= -tree-kill@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" - integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== - trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -16602,11 +16184,6 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== -ts-interface-checker@^0.1.9: - version "0.1.13" - resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" - integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== - ts-node@8.9.1: version "8.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.9.1.tgz#2f857f46c47e91dcd28a14e052482eb14cfd65a5" @@ -16633,28 +16210,6 @@ tslib@^2.3.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== -tsup@^8.3.5: - version "8.3.6" - resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.3.6.tgz#a10eb2dc27f84b510a0f00341ab75cad03d13a88" - integrity sha512-XkVtlDV/58S9Ye0JxUUTcrQk4S+EqlOHKzg6Roa62rdjL1nGWNUstG0xgI4vanHdfIpjP448J8vlN0oK6XOJ5g== - dependencies: - bundle-require "^5.0.0" - cac "^6.7.14" - chokidar "^4.0.1" - consola "^3.2.3" - debug "^4.3.7" - esbuild "^0.24.0" - joycon "^3.1.1" - picocolors "^1.1.1" - postcss-load-config "^6.0.1" - resolve-from "^5.0.0" - rollup "^4.24.0" - source-map "0.8.0-beta.0" - sucrase "^3.35.0" - tinyexec "^0.3.1" - tinyglobby "^0.2.9" - tree-kill "^1.2.2" - tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" @@ -17287,11 +16842,6 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== - webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" @@ -17462,15 +17012,6 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - when@3.7.7: version "3.7.7" resolved "https://registry.yarnpkg.com/when/-/when-3.7.7.tgz#aba03fc3bb736d6c88b091d013d8a8e590d84718" From be91130f184f04c6e7bb9ff18222aba2ef2f96f6 Mon Sep 17 00:00:00 2001 From: michael faith Date: Sun, 16 Feb 2025 15:14:43 -0600 Subject: [PATCH 04/13] chore: remove `devEngines` declaration in root package (#32398) This change removes the `devEngines` declaration in the root package. It didn't match the package.json spec and in npm 10.9.0 (released in October), a breaking change was introduced that checks the `devEngines` property. This causes `npm pack` calls to fail, due to the malformed `devEngines`. Since there's already an `.nvmrc` defined in the repo, and no strong need to enforce a specific node version for local development, this removes the declaration altogether. --- package.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/package.json b/package.json index 95fffa700a..8e5dae3f94 100644 --- a/package.json +++ b/package.json @@ -106,9 +106,6 @@ "web-streams-polyfill": "^3.1.1", "yargs": "^15.3.1" }, - "devEngines": { - "node": "16.x || 18.x || 20.x || 22.x" - }, "jest": { "testRegex": "/scripts/jest/dont-run-jest-directly\\.js$" }, @@ -122,7 +119,7 @@ "lint": "node ./scripts/tasks/eslint.js", "lint-build": "node ./scripts/rollup/validate/index.js", "extract-errors": "node scripts/error-codes/extract-errors.js", - "postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json && node ./scripts/flow/createFlowConfigs.js", + "postinstall": "node ./scripts/flow/createFlowConfigs.js", "test": "node ./scripts/jest/jest-cli.js", "test-stable": "node ./scripts/jest/jest-cli.js --release-channel=stable", "test-www": "node ./scripts/jest/jest-cli.js --release-channel=www-modern", From eb1f77dedfc8f7491ecd39b160e4743fa39dfc99 Mon Sep 17 00:00:00 2001 From: michael faith Date: Sun, 16 Feb 2025 16:00:43 -0600 Subject: [PATCH 05/13] ci: add workflow for running the eslint plugin e2e tests (#32397) This change adds a workflow for PR builds, that runs the e2e tests for `eslint-plugin-react-hooks` created in #32396 ![screenshot of ci tests running](https://github.com/user-attachments/assets/307a878c-92b5-44cf-84f2-3b21979b262a) --- .../workflows/runtime_eslint_plugin_e2e.yml | 56 +++++++++++++++++++ fixtures/eslint-v6/build.mjs | 9 ++- fixtures/eslint-v6/package.json | 2 +- fixtures/eslint-v6/yarn.lock | 2 +- fixtures/eslint-v7/build.mjs | 9 ++- fixtures/eslint-v7/package.json | 2 +- fixtures/eslint-v7/yarn.lock | 2 +- fixtures/eslint-v8/build.mjs | 9 ++- fixtures/eslint-v8/package.json | 2 +- fixtures/eslint-v8/yarn.lock | 2 +- fixtures/eslint-v9/build.mjs | 9 ++- fixtures/eslint-v9/package.json | 2 +- fixtures/eslint-v9/yarn.lock | 2 +- 13 files changed, 96 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/runtime_eslint_plugin_e2e.yml diff --git a/.github/workflows/runtime_eslint_plugin_e2e.yml b/.github/workflows/runtime_eslint_plugin_e2e.yml new file mode 100644 index 0000000000..a6f0bf28f0 --- /dev/null +++ b/.github/workflows/runtime_eslint_plugin_e2e.yml @@ -0,0 +1,56 @@ +name: (Runtime) ESLint Plugin E2E + +on: + push: + branches: [main] + pull_request: + paths-ignore: + - compiler/** + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + +jobs: + # ----- TESTS ----- + test: + name: ESLint v${{ matrix.eslint_major }} + runs-on: ubuntu-latest + strategy: + matrix: + eslint_major: + - "6" + - "7" + - "8" + - "9" + continue-on-error: true + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: yarn + cache-dependency-path: yarn.lock + - name: Restore cached node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: "**/node_modules" + key: runtime-eslint_e2e-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + - name: Build plugin + working-directory: fixtures/eslint-v${{ matrix.eslint_major }} + run: node build.mjs + - name: Install fixture dependencies + working-directory: ./fixtures/eslint-v${{ matrix.eslint_major }} + run: yarn --frozen-lockfile + - name: Run lint test + working-directory: ./fixtures/eslint-v${{ matrix.eslint_major }} + run: yarn lint diff --git a/fixtures/eslint-v6/build.mjs b/fixtures/eslint-v6/build.mjs index 02a1bbd25e..ebcea15190 100644 --- a/fixtures/eslint-v6/build.mjs +++ b/fixtures/eslint-v6/build.mjs @@ -1,5 +1,12 @@ #!/usr/bin/env node import {exec} from 'node:child_process'; +import {dirname, resolve} from 'node:path'; +import {fileURLToPath} from 'node:url'; -exec('cd ../.. && yarn build -r stable eslint-plugin-react-hooks'); +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +exec('yarn build -r stable eslint-plugin-react-hooks', { + cwd: resolve(__dirname, '..', '..'), +}); diff --git a/fixtures/eslint-v6/package.json b/fixtures/eslint-v6/package.json index 50c92054b4..c410edd78f 100644 --- a/fixtures/eslint-v6/package.json +++ b/fixtures/eslint-v6/package.json @@ -3,7 +3,7 @@ "name": "eslint-v6", "dependencies": { "eslint": "^6", - "eslint-plugin-react-hooks": "link:../../build/node_modules/eslint-plugin-react-hooks" + "eslint-plugin-react-hooks": "link:../../build/oss-stable/eslint-plugin-react-hooks" }, "scripts": { "build": "node build.mjs && yarn", diff --git a/fixtures/eslint-v6/yarn.lock b/fixtures/eslint-v6/yarn.lock index 3d6dbca037..5af9623e87 100644 --- a/fixtures/eslint-v6/yarn.lock +++ b/fixtures/eslint-v6/yarn.lock @@ -205,7 +205,7 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -"eslint-plugin-react-hooks@link:../../build/node_modules/eslint-plugin-react-hooks": +"eslint-plugin-react-hooks@link:../../build/oss-stable/eslint-plugin-react-hooks": version "0.0.0" uid "" diff --git a/fixtures/eslint-v7/build.mjs b/fixtures/eslint-v7/build.mjs index 02a1bbd25e..ebcea15190 100644 --- a/fixtures/eslint-v7/build.mjs +++ b/fixtures/eslint-v7/build.mjs @@ -1,5 +1,12 @@ #!/usr/bin/env node import {exec} from 'node:child_process'; +import {dirname, resolve} from 'node:path'; +import {fileURLToPath} from 'node:url'; -exec('cd ../.. && yarn build -r stable eslint-plugin-react-hooks'); +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +exec('yarn build -r stable eslint-plugin-react-hooks', { + cwd: resolve(__dirname, '..', '..'), +}); diff --git a/fixtures/eslint-v7/package.json b/fixtures/eslint-v7/package.json index 90c369c603..5e64917514 100644 --- a/fixtures/eslint-v7/package.json +++ b/fixtures/eslint-v7/package.json @@ -3,7 +3,7 @@ "name": "eslint-v7", "dependencies": { "eslint": "^7", - "eslint-plugin-react-hooks": "link:../../build/node_modules/eslint-plugin-react-hooks" + "eslint-plugin-react-hooks": "link:../../build/oss-stable/eslint-plugin-react-hooks" }, "scripts": { "build": "node build.mjs && yarn", diff --git a/fixtures/eslint-v7/yarn.lock b/fixtures/eslint-v7/yarn.lock index 62f97bbc20..4a191de947 100644 --- a/fixtures/eslint-v7/yarn.lock +++ b/fixtures/eslint-v7/yarn.lock @@ -234,7 +234,7 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -"eslint-plugin-react-hooks@link:../../build/node_modules/eslint-plugin-react-hooks": +"eslint-plugin-react-hooks@link:../../build/oss-stable/eslint-plugin-react-hooks": version "0.0.0" uid "" diff --git a/fixtures/eslint-v8/build.mjs b/fixtures/eslint-v8/build.mjs index 02a1bbd25e..ebcea15190 100644 --- a/fixtures/eslint-v8/build.mjs +++ b/fixtures/eslint-v8/build.mjs @@ -1,5 +1,12 @@ #!/usr/bin/env node import {exec} from 'node:child_process'; +import {dirname, resolve} from 'node:path'; +import {fileURLToPath} from 'node:url'; -exec('cd ../.. && yarn build -r stable eslint-plugin-react-hooks'); +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +exec('yarn build -r stable eslint-plugin-react-hooks', { + cwd: resolve(__dirname, '..', '..'), +}); diff --git a/fixtures/eslint-v8/package.json b/fixtures/eslint-v8/package.json index 620520ecdb..ed3de107c5 100644 --- a/fixtures/eslint-v8/package.json +++ b/fixtures/eslint-v8/package.json @@ -3,7 +3,7 @@ "name": "eslint-v8", "dependencies": { "eslint": "^8", - "eslint-plugin-react-hooks": "link:../../build/node_modules/eslint-plugin-react-hooks" + "eslint-plugin-react-hooks": "link:../../build/oss-stable/eslint-plugin-react-hooks" }, "scripts": { "build": "node build.mjs && yarn", diff --git a/fixtures/eslint-v8/yarn.lock b/fixtures/eslint-v8/yarn.lock index 88d0402995..d5a947b634 100644 --- a/fixtures/eslint-v8/yarn.lock +++ b/fixtures/eslint-v8/yarn.lock @@ -192,7 +192,7 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -"eslint-plugin-react-hooks@link:../../build/node_modules/eslint-plugin-react-hooks": +"eslint-plugin-react-hooks@link:../../build/oss-stable/eslint-plugin-react-hooks": version "0.0.0" uid "" diff --git a/fixtures/eslint-v9/build.mjs b/fixtures/eslint-v9/build.mjs index 02a1bbd25e..ebcea15190 100644 --- a/fixtures/eslint-v9/build.mjs +++ b/fixtures/eslint-v9/build.mjs @@ -1,5 +1,12 @@ #!/usr/bin/env node import {exec} from 'node:child_process'; +import {dirname, resolve} from 'node:path'; +import {fileURLToPath} from 'node:url'; -exec('cd ../.. && yarn build -r stable eslint-plugin-react-hooks'); +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +exec('yarn build -r stable eslint-plugin-react-hooks', { + cwd: resolve(__dirname, '..', '..'), +}); diff --git a/fixtures/eslint-v9/package.json b/fixtures/eslint-v9/package.json index e8ae91a061..58d0a94c0c 100644 --- a/fixtures/eslint-v9/package.json +++ b/fixtures/eslint-v9/package.json @@ -3,7 +3,7 @@ "name": "eslint-v9", "dependencies": { "eslint": "^9", - "eslint-plugin-react-hooks": "link:../../build/node_modules/eslint-plugin-react-hooks" + "eslint-plugin-react-hooks": "link:../../build/oss-stable/eslint-plugin-react-hooks" }, "scripts": { "build": "node build.mjs && yarn", diff --git a/fixtures/eslint-v9/yarn.lock b/fixtures/eslint-v9/yarn.lock index 5a1a246827..1583b73f14 100644 --- a/fixtures/eslint-v9/yarn.lock +++ b/fixtures/eslint-v9/yarn.lock @@ -209,7 +209,7 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -"eslint-plugin-react-hooks@link:../../build/node_modules/eslint-plugin-react-hooks": +"eslint-plugin-react-hooks@link:../../build/oss-stable/eslint-plugin-react-hooks": version "0.0.0" uid "" From 4632e36a4ef16a1af24987c56e42b664f6403e64 Mon Sep 17 00:00:00 2001 From: michael faith Date: Sun, 16 Feb 2025 19:28:12 -0600 Subject: [PATCH 06/13] refactor(eslint-plugin-react-hooks): change array type and improve conditionals (#32400) - [build(eslint-plugin-react-hooks): add ts-linting](https://github.com/facebook/react/commit/4c0fbe73d9abc2681445f62b9450737f3df12ee2) This change adds configuration to the eslint config governing `eslint-plugin-react-hooks` to use the typescript-eslint plugin and parser. It adds the typescript-recommended config, and configures the team's preferred `array-type` convention. - [refactor(eslint-plugin-react-hooks): improve conditionals](https://github.com/facebook/react/commit/540d0d95bc5172ef95ccc2ad70b4b202b6eeedd2) This change addresses several feedback items from https://github.com/facebook/react/pull/32240 - [ci (eslint-e2e): exclude nested node_modules from cache](https://github.com/facebook/react/pull/32400/commits/a3279f46a85cfb4ddea5a863a6f7c71344280d36) This change removes the nested fixture `node_modules` from being cached, so that the symbolic link can be made after the build happens. --- .eslintrc.js | 25 ++++++++-- .../workflows/runtime_eslint_plugin_e2e.yml | 2 +- package.json | 2 + .../src/ExhaustiveDeps.ts | 32 ++++++------ .../src/RulesOfHooks.ts | 12 +++-- yarn.lock | 50 ++++++++++++++++++- 6 files changed, 97 insertions(+), 26 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 7fe08f4cdf..360bd5ba76 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -446,10 +446,7 @@ module.exports = { }, }, { - files: [ - 'scripts/eslint-rules/*.js', - 'packages/eslint-plugin-react-hooks/src/*.js', - ], + files: ['scripts/eslint-rules/*.js'], plugins: ['eslint-plugin'], rules: { 'eslint-plugin/prefer-object-rule': ERROR, @@ -517,6 +514,26 @@ module.exports = { __IS_INTERNAL_VERSION__: 'readonly', }, }, + { + files: ['packages/eslint-plugin-react-hooks/src/**/*'], + extends: ['plugin:@typescript-eslint/recommended'], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint', 'eslint-plugin'], + rules: { + '@typescript-eslint/no-explicit-any': OFF, + '@typescript-eslint/no-non-null-assertion': OFF, + '@typescript-eslint/array-type': [ERROR, {default: 'generic'}], + + 'es/no-optional-chaining': OFF, + + 'eslint-plugin/prefer-object-rule': ERROR, + 'eslint-plugin/require-meta-fixable': [ + ERROR, + {catchNoFixerButFixableProperty: true}, + ], + 'eslint-plugin/require-meta-has-suggestions': ERROR, + }, + }, ], env: { diff --git a/.github/workflows/runtime_eslint_plugin_e2e.yml b/.github/workflows/runtime_eslint_plugin_e2e.yml index a6f0bf28f0..edc188f386 100644 --- a/.github/workflows/runtime_eslint_plugin_e2e.yml +++ b/.github/workflows/runtime_eslint_plugin_e2e.yml @@ -40,7 +40,7 @@ jobs: uses: actions/cache@v4 id: node_modules with: - path: "**/node_modules" + path: "node_modules" key: runtime-eslint_e2e-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - name: Ensure clean build directory run: rm -rf build diff --git a/package.json b/package.json index 8e5dae3f94..0a2b6c3024 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,8 @@ "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-typescript": "^12.1.2", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", "abortcontroller-polyfill": "^1.7.5", "art": "0.10.1", "babel-plugin-syntax-trailing-function-commas": "^6.5.0", diff --git a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.ts b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.ts index 9f3d4d4db9..1b00597572 100644 --- a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.ts +++ b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.ts @@ -28,7 +28,7 @@ type DeclaredDependency = { type Dependency = { isStable: boolean; - references: Scope.Reference[]; + references: Array; }; type DependencyTreeNode = { @@ -184,7 +184,9 @@ const rule = { // Get the current scope. const scope = scopeManager.acquire(node); if (!scope) { - return; + throw new Error( + 'Unable to acquire scope for the current node. This is a bug in eslint-plugin-react-hooks, please file an issue.', + ); } // Find all our "pure scopes". On every re-render of a component these @@ -255,7 +257,7 @@ const rule = { // Detect primitive constants // const foo = 42 let declaration = defNode.parent; - if (declaration == null && componentScope) { + if (declaration == null && componentScope != null) { // This might happen if variable is declared after the callback. // In that case ESLint won't set up .parent refs. // So we'll set them up manually. @@ -266,7 +268,7 @@ const rule = { } } if ( - declaration && + declaration != null && 'kind' in declaration && declaration.kind === 'const' && init.type === 'Literal' && @@ -454,7 +456,7 @@ const rule = { function isInsideEffectCleanup(reference: Scope.Reference): boolean { let curScope: Scope.Scope | null = reference.from; let isInReturnedFunction = false; - while (curScope && curScope.block !== node) { + while (curScope != null && curScope.block !== node) { if (curScope.type === 'function') { isInReturnedFunction = curScope.block.parent != null && @@ -529,7 +531,7 @@ const rule = { continue; } // Ignore references to the function itself as it's not defined yet. - if (def.node && def.node.init === node.parent) { + if (def.node != null && def.node.init === node.parent) { continue; } // Ignore Flow type parameters @@ -566,8 +568,8 @@ const rule = { // Is React managing this ref or us? // Let's see if we can find a .current assignment. let foundCurrentAssignment = false; - for (const reference of references) { - const {identifier} = reference; + for (const ref of references) { + const {identifier} = ref; const {parent} = identifier; if ( parent != null && @@ -660,7 +662,7 @@ const rule = { } let fnScope: Scope.Scope | null = reference.from; - while (fnScope && fnScope.type !== 'function') { + while (fnScope != null && fnScope.type !== 'function') { fnScope = fnScope.upper; } const isDirectlyInsideEffect = fnScope?.block === node; @@ -704,7 +706,7 @@ const rule = { return; } - const declaredDependencies: DeclaredDependency[] = []; + const declaredDependencies: Array = []; const externalDependencies = new Set(); const isArrayExpression = declaredDependenciesNode.type === 'ArrayExpression'; @@ -1469,7 +1471,7 @@ function collectRecommendations({ isEffect, }: { dependencies: Map; - declaredDependencies: DeclaredDependency[]; + declaredDependencies: Array; stableDependencies: Set; externalDependencies: Set; isEffect: boolean; @@ -1592,7 +1594,7 @@ function collectRecommendations({ } // Collect suggestions in the order they were originally specified. - const suggestedDependencies: string[] = []; + const suggestedDependencies: Array = []; const unnecessaryDependencies = new Set(); const duplicateDependencies = new Set(); declaredDependencies.forEach(({key}) => { @@ -1699,7 +1701,7 @@ function scanForConstructions({ componentScope, scope, }: { - declaredDependencies: DeclaredDependency[]; + declaredDependencies: Array; declaredDependenciesNode: Node; componentScope: Scope.Scope; scope: Scope.Scope; @@ -1747,7 +1749,7 @@ function scanForConstructions({ } return null; }) - .filter(Boolean) as [Scope.Variable, string][]; + .filter(Boolean) as Array<[Scope.Variable, string]>; function isUsedOutsideOfHook(ref: Scope.Variable): boolean { let foundWriteExpr = false; @@ -2007,7 +2009,7 @@ function fastFindReferenceWithParent(start: Node, target: Node): Node | null { return null; } -function joinEnglish(arr: string[]): string { +function joinEnglish(arr: Array): string { let s = ''; for (let i = 0; i < arr.length; i++) { s += arr[i]; diff --git a/packages/eslint-plugin-react-hooks/src/RulesOfHooks.ts b/packages/eslint-plugin-react-hooks/src/RulesOfHooks.ts index 24870d7161..0ab0c5ff21 100644 --- a/packages/eslint-plugin-react-hooks/src/RulesOfHooks.ts +++ b/packages/eslint-plugin-react-hooks/src/RulesOfHooks.ts @@ -130,8 +130,10 @@ const rule = { }, create(context: Rule.RuleContext) { let lastEffect: CallExpression | null = null; - const codePathReactHooksMapStack: Map[] = []; - const codePathSegmentStack: Rule.CodePathSegment[] = []; + const codePathReactHooksMapStack: Array< + Map> + > = []; + const codePathSegmentStack: Array = []; const useEffectEventFunctions = new WeakSet(); // For a given scope, iterate through the references and add all useEffectEvent definitions. We can @@ -190,7 +192,7 @@ const rule = { // Maintain code path stack as we traverse. onCodePathStart: () => codePathReactHooksMapStack.push( - new Map(), + new Map>(), ), // Process our code path. @@ -561,7 +563,7 @@ const rule = { context.report({node: hook, message}); } } else if ( - codePathNode.parent && + codePathNode.parent != null && (codePathNode.parent.type === 'MethodDefinition' || // @ts-expect-error `ClassProperty` was removed from typescript-estree in https://github.com/typescript-eslint/typescript-eslint/pull/3806 codePathNode.parent.type === 'ClassProperty' || @@ -758,7 +760,7 @@ function getFunctionName(node: Node) { /** * Convenience function for peeking the last item in a stack. */ -function last(array: T[]): T { +function last(array: Array): T { return array[array.length - 1] as T; } diff --git a/yarn.lock b/yarn.lock index ba71ba7abe..7bc936afae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2410,6 +2410,11 @@ dependencies: eslint-visitor-keys "^3.3.0" +"@eslint-community/regexpp@^4.5.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + "@eslint-community/regexpp@^4.6.1": version "4.10.0" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" @@ -3718,6 +3723,23 @@ dependencies: "@types/node" "*" +"@typescript-eslint/eslint-plugin@^6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3" + integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/type-utils" "6.21.0" + "@typescript-eslint/utils" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/experimental-utils@2.34.0": version "2.34.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" @@ -3780,6 +3802,17 @@ "@typescript-eslint/typescript-estree" "5.62.0" debug "^4.3.4" +"@typescript-eslint/parser@^6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" + integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== + dependencies: + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + "@typescript-eslint/scope-manager@4.1.0": version "4.1.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.1.0.tgz#9e389745ee9cfe12252ed1e9958808abd6b3a683" @@ -3804,6 +3837,16 @@ "@typescript-eslint/types" "6.21.0" "@typescript-eslint/visitor-keys" "6.21.0" +"@typescript-eslint/type-utils@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e" + integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag== + dependencies: + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/utils" "6.21.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/types@3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" @@ -3892,7 +3935,7 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@^6.0.0": +"@typescript-eslint/utils@6.21.0", "@typescript-eslint/utils@^6.0.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134" integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ== @@ -9799,6 +9842,11 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== +ignore@^5.2.4: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + image-size@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.1.1.tgz#ddd67d4dc340e52ac29ce5f546a09f4e29e840ac" From 8a7b487e3b171c91f2fe18e9142af53f4dd83454 Mon Sep 17 00:00:00 2001 From: Ricky Date: Tue, 18 Feb 2025 10:29:40 -0500 Subject: [PATCH 07/13] [flags] enable owner stacks everywhere (#32376) this is now canary and on everywhere --- .../shared/forks/ReactFeatureFlags.native-fb-dynamic.js | 2 -- packages/shared/forks/ReactFeatureFlags.native-fb.js | 6 ++++-- packages/shared/forks/ReactFeatureFlags.native-oss.js | 4 ++-- .../forks/ReactFeatureFlags.test-renderer.native-fb.js | 4 ++-- .../shared/forks/ReactFeatureFlags.test-renderer.www.js | 4 ++-- packages/shared/forks/ReactFeatureFlags.www-dynamic.js | 2 -- packages/shared/forks/ReactFeatureFlags.www.js | 6 ++++-- scripts/jest/setupTests.www.js | 1 + scripts/jest/setupTests.xplat.js | 2 ++ 9 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js index ffcec9334d..d3c5de81bd 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -25,7 +25,5 @@ export const enableShallowPropDiffing = __VARIANT__; export const passChildrenWhenCloningPersistedNodes = __VARIANT__; export const enableSiblingPrerendering = __VARIANT__; export const enableUseEffectCRUDOverload = __VARIANT__; -export const enableOwnerStacks = __VARIANT__; -export const enableRemoveConsolePatches = __VARIANT__; export const enableFastAddPropertiesInDiffing = __VARIANT__; export const enableLazyPublicInstanceInFabric = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 470e148959..a0544dc161 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -27,12 +27,14 @@ export const { enableUseEffectCRUDOverload, passChildrenWhenCloningPersistedNodes, enableSiblingPrerendering, - enableOwnerStacks, - enableRemoveConsolePatches, enableFastAddPropertiesInDiffing, enableLazyPublicInstanceInFabric, } = dynamicFlags; +// These two can be removed +export const enableOwnerStacks = true; +export const enableRemoveConsolePatches = true; + // The rest of the flags are static for better dead code elimination. export const disableClientCache = true; export const disableCommentsAsDOMContainers = true; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 361ebde413..fd846cf312 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -40,7 +40,7 @@ export const enableLegacyFBSupport = false; export const enableLegacyHidden = false; export const enableNoCloningMemoCache = false; export const enableObjectFiber = false; -export const enableOwnerStacks = false; +export const enableOwnerStacks = true; export const enablePersistedModeClonedFlag = false; export const enablePostpone = false; export const enableReactTestRendererWarning = false; @@ -80,7 +80,7 @@ export const enableProfilerTimer = __PROFILE__; export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; export const enableUpdaterTracking = __PROFILE__; -export const enableRemoveConsolePatches = false; +export const enableRemoveConsolePatches = true; // Flow magic to verify the exports of this file match the original version. ((((null: any): ExportsType): FeatureFlagsType): ExportsType); diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 18172fdfe5..e4f1210c29 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -35,7 +35,7 @@ export const enableLegacyFBSupport = false; export const enableLegacyHidden = false; export const enableNoCloningMemoCache = false; export const enableObjectFiber = false; -export const enableOwnerStacks = false; +export const enableOwnerStacks = true; export const enablePersistedModeClonedFlag = false; export const enablePostpone = false; export const enableProfilerCommitHooks = __PROFILE__; @@ -67,8 +67,8 @@ export const enableHydrationLaneScheduling = true; export const enableYieldingBeforePassive = false; export const enableThrottledScheduling = false; export const enableViewTransition = false; +export const enableRemoveConsolePatches = true; export const enableSwipeTransition = false; -export const enableRemoveConsolePatches = false; export const enableFastAddPropertiesInDiffing = false; export const enableLazyPublicInstanceInFabric = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 628a834133..112b30fe04 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -70,7 +70,7 @@ export const disableDefaultPropsExceptForClasses = true; export const renameElementSymbol = false; export const enableObjectFiber = false; -export const enableOwnerStacks = false; +export const enableOwnerStacks = true; export const enableShallowPropDiffing = false; export const enableSiblingPrerendering = true; @@ -82,8 +82,8 @@ export const enableYieldingBeforePassive = false; export const enableThrottledScheduling = false; export const enableViewTransition = false; +export const enableRemoveConsolePatches = true; export const enableSwipeTransition = false; -export const enableRemoveConsolePatches = false; export const enableFastAddPropertiesInDiffing = false; export const enableLazyPublicInstanceInFabric = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index d0b4404a3e..e0f431fe7f 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -26,7 +26,6 @@ export const enableRetryLaneExpiration = __VARIANT__; export const enableTransitionTracing = __VARIANT__; export const favorSafetyOverHydrationPerf = __VARIANT__; export const renameElementSymbol = __VARIANT__; -export const enableOwnerStacks = __VARIANT__; export const retryLaneExpirationMs = 5000; export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; @@ -37,7 +36,6 @@ export const enableInfiniteRenderLoopDetection = __VARIANT__; export const enableSiblingPrerendering = __VARIANT__; export const enableUseEffectCRUDOverload = __VARIANT__; -export const enableRemoveConsolePatches = __VARIANT__; export const enableFastAddPropertiesInDiffing = __VARIANT__; export const enableLazyPublicInstanceInFabric = false; export const enableViewTransition = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 5932c6eddf..ec0337382e 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -35,8 +35,6 @@ export const { retryLaneExpirationMs, syncLaneExpirationMs, transitionLaneExpirationMs, - enableOwnerStacks, - enableRemoveConsolePatches, enableFastAddPropertiesInDiffing, enableViewTransition, } = dynamicFeatureFlags; @@ -44,6 +42,10 @@ export const { // On WWW, __EXPERIMENTAL__ is used for a new modern build. // It's not used anywhere in production yet. +// Can remove these two +export const enableOwnerStacks = true; +export const enableRemoveConsolePatches = true; + export const enableProfilerTimer = __PROFILE__; export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; diff --git a/scripts/jest/setupTests.www.js b/scripts/jest/setupTests.www.js index b0b653bb78..9ac7ffc6db 100644 --- a/scripts/jest/setupTests.www.js +++ b/scripts/jest/setupTests.www.js @@ -11,6 +11,7 @@ jest.mock('shared/ReactFeatureFlags', () => { // Flags that aren't currently used, but we still want to force variants to keep the // code live. actual.disableInputAttributeSyncing = __VARIANT__; + actual.enableOwnerStacks = __VARIANT__; // These are hardcoded to true for the next release, // but still run the tests against both variants until diff --git a/scripts/jest/setupTests.xplat.js b/scripts/jest/setupTests.xplat.js index 859a506598..87fbf8bef8 100644 --- a/scripts/jest/setupTests.xplat.js +++ b/scripts/jest/setupTests.xplat.js @@ -11,6 +11,8 @@ jest.mock('shared/ReactFeatureFlags', () => { 'shared/forks/ReactFeatureFlags.native-fb.js' ); + actual.enableOwnerStacks = __VARIANT__; + // Lots of tests use these, but we don't want to expose it to RN. // Ideally, tests for xplat wouldn't use react-dom, but many of our tests do. // Since the xplat tests run with the www entry points, some of these flags From 7c0c9abea0ea75c6eb130fa6de54911a12046dca Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Tue, 18 Feb 2025 09:16:26 -0700 Subject: [PATCH 08/13] [compiler] Delete LoweredFunction.dependencies and hoisted instructions LoweredFunction dependencies were exclusively used for dependency extraction (in `propagateScopeDeps`). Now that we have a `propagateScopeDepsHIR` that recursively traverses into nested functions, we can delete `dependencies` and their associated synthetic `LoadLocal`/`PropertyLoad` instructions. [Internal snapshot diff](https://www.internalfb.com/phabricator/paste/view/P1716950202) for this change shows ~.2% of files changed. I [read through ~60 of the changed files](https://www.internalfb.com/phabricator/paste/view/P1733074307) - most changes are due to better outlining (due to better DCE) - a few changes in memo inference are due to changed ordering ``` // source arr.map(() => contextVar.inner); // previous instructions $0 = LoadLocal arr $1 = $0.map // Below instructions are synthetic $2 = LoadLocal contextVar $3 = $2.inner $4 = Function deps=$3 context=contextVar { ... } ``` - a few changes are effectively bugfixes (see `aliased-nested-scope-fn-expr`) --- .../src/HIR/BuildHIR.ts | 154 +----------- .../src/HIR/CollectHoistablePropertyLoads.ts | 37 +-- .../src/HIR/Environment.ts | 2 - .../src/HIR/HIR.ts | 1 - .../HIR/MergeOverlappingReactiveScopesHIR.ts | 17 +- .../src/HIR/PrintHIR.ts | 5 +- .../src/HIR/PropagateScopeDependenciesHIR.ts | 5 +- .../src/HIR/visitors.ts | 7 +- .../src/Inference/AnalyseFunctions.ts | 146 +++--------- .../Inference/InferMutableContextVariables.ts | 23 +- .../src/Inference/InferReferenceEffects.ts | 48 ++-- .../src/Optimization/LowerContextAccess.ts | 1 - .../src/Optimization/OutlineFunctions.ts | 1 - .../InferReactiveScopeVariables.ts | 8 + .../src/SSA/EliminateRedundantPhi.ts | 19 ++ .../src/SSA/EnterSSA.ts | 3 - .../src/Transform/TransformFire.ts | 53 +---- .../aliased-nested-scope-fn-expr.expect.md | 120 ++++++++++ .../compiler/aliased-nested-scope-fn-expr.tsx | 46 ++++ ...iased-nested-scope-truncated-dep.expect.md | 221 ++++++++++++++++++ .../aliased-nested-scope-truncated-dep.tsx | 93 ++++++++ ...access-in-unused-callback-nested.expect.md | 40 ++-- .../capturing-func-mutate-2.expect.md | 1 - .../capturing-func-no-mutate.expect.md | 12 +- ...capturing-func-simple-alias-iife.expect.md | 1 - ...ction-alias-computed-load-2-iife.expect.md | 1 - ...ction-alias-computed-load-3-iife.expect.md | 2 - ...ction-alias-computed-load-4-iife.expect.md | 1 - ...unction-alias-computed-load-iife.expect.md | 1 - ...capturing-reference-changes-type.expect.md | 1 - .../codegen-inline-iife-reassign.expect.md | 3 +- ...-into-function-expression-global.expect.md | 7 +- ...to-function-expression-primitive.expect.md | 7 +- ...gation-into-function-expressions.expect.md | 9 +- ...text-variable-as-jsx-element-tag.expect.md | 3 +- ...ting-simple-function-declaration.expect.md | 10 +- ...call-freezes-captured-identifier.expect.md | 41 ++++ ....hook-call-freezes-captured-identifier.tsx | 20 ++ ...call-freezes-captured-memberexpr.expect.md | 41 ++++ ....hook-call-freezes-captured-memberexpr.jsx | 20 ++ ...on-with-shadowed-local-same-name.expect.md | 2 +- ...setstate-captured-indirectly-jsx.expect.md | 81 +++++++ ...isting-setstate-captured-indirectly-jsx.js | 17 ++ .../compiler/hoisting-setstate.expect.md | 77 ++++++ .../fixtures/compiler/hoisting-setstate.js | 28 +++ ...call-freezes-captured-memberexpr.expect.md | 87 +++++++ .../hook-call-freezes-captured-memberexpr.tsx | 21 ++ .../jsx-local-tag-in-lambda.expect.md | 7 +- .../jsx-memberexpr-tag-in-lambda.expect.md | 7 +- ...mutated-non-reactive-to-reactive.expect.md | 1 - .../lambda-mutated-ref-non-reactive.expect.md | 1 - ...ed-function-shadowed-identifiers.expect.md | 5 +- ...o-reordering-depslist-assignment.expect.md | 1 - ...e-phis-in-lambda-capture-context.expect.md | 29 +-- .../use-operator-conditional.expect.md | 1 - 55 files changed, 1123 insertions(+), 473 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-fn-expr.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-fn-expr.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-identifier.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-identifier.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-memberexpr.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-memberexpr.jsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-call-freezes-captured-memberexpr.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-call-freezes-captured-memberexpr.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index d5c3ea6a49..67cdcab038 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -7,7 +7,6 @@ import {NodePath, Scope} from '@babel/traverse'; import * as t from '@babel/types'; -import {Expression} from '@babel/types'; import invariant from 'invariant'; import { CompilerError, @@ -75,7 +74,7 @@ export function lower( parent: NodePath | null = null, ): Result { const builder = new HIRBuilder(env, parent ?? func, bindings, capturedRefs); - const context: Array = []; + const context: HIRFunction['context'] = []; for (const ref of capturedRefs ?? []) { context.push({ @@ -3378,7 +3377,7 @@ function lowerFunction( >, ): LoweredFunction | null { const componentScope: Scope = builder.parentFunction.scope; - const captured = gatherCapturedDeps(builder, expr, componentScope); + const capturedContext = gatherCapturedContext(expr, componentScope); /* * TODO(gsn): In the future, we could only pass in the context identifiers @@ -3392,7 +3391,7 @@ function lowerFunction( expr, builder.environment, builder.bindings, - [...builder.context, ...captured.identifiers], + [...builder.context, ...capturedContext], builder.parentFunction, ); let loweredFunc: HIRFunction; @@ -3405,7 +3404,6 @@ function lowerFunction( loweredFunc = lowering.unwrap(); return { func: loweredFunc, - dependencies: captured.refs, }; } @@ -4079,14 +4077,6 @@ function lowerAssignment( } } -function isValidDependency(path: NodePath): boolean { - const parent: NodePath = path.parentPath; - return ( - !path.node.computed && - !(parent.isCallExpression() && parent.get('callee') === path) - ); -} - function captureScopes({from, to}: {from: Scope; to: Scope}): Set { let scopes: Set = new Set(); while (from) { @@ -4101,8 +4091,7 @@ function captureScopes({from, to}: {from: Scope; to: Scope}): Set { return scopes; } -function gatherCapturedDeps( - builder: HIRBuilder, +function gatherCapturedContext( fn: NodePath< | t.FunctionExpression | t.ArrowFunctionExpression @@ -4110,10 +4099,8 @@ function gatherCapturedDeps( | t.ObjectMethod >, componentScope: Scope, -): {identifiers: Array; refs: Array} { - const capturedIds: Map = new Map(); - const capturedRefs: Set = new Set(); - const seenPaths: Set = new Set(); +): Array { + const capturedIds = new Set(); /* * Capture all the scopes from the parent of this function up to and including @@ -4124,33 +4111,11 @@ function gatherCapturedDeps( to: componentScope, }); - function addCapturedId(bindingIdentifier: t.Identifier): number { - if (!capturedIds.has(bindingIdentifier)) { - const index = capturedIds.size; - capturedIds.set(bindingIdentifier, index); - return index; - } else { - return capturedIds.get(bindingIdentifier)!; - } - } - function handleMaybeDependency( - path: - | NodePath - | NodePath - | NodePath, + path: NodePath | NodePath, ): void { // Base context variable to depend on let baseIdentifier: NodePath | NodePath; - /* - * Base expression to depend on, which (for now) may contain non side-effectful - * member expressions - */ - let dependency: - | NodePath - | NodePath - | NodePath - | NodePath; if (path.isJSXOpeningElement()) { const name = path.get('name'); if (!(name.isJSXMemberExpression() || name.isJSXIdentifier())) { @@ -4166,115 +4131,20 @@ function gatherCapturedDeps( 'Invalid logic in gatherCapturedDeps', ); baseIdentifier = current; - - /* - * Get the expression to depend on, which may involve PropertyLoads - * for member expressions - */ - let currentDep: - | NodePath - | NodePath - | NodePath = baseIdentifier; - - while (true) { - const nextDep: null | NodePath = currentDep.parentPath; - if (nextDep && nextDep.isJSXMemberExpression()) { - currentDep = nextDep; - } else { - break; - } - } - dependency = currentDep; - } else if (path.isMemberExpression()) { - // Calculate baseIdentifier - let currentId: NodePath = path; - while (currentId.isMemberExpression()) { - currentId = currentId.get('object'); - } - if (!currentId.isIdentifier()) { - return; - } - baseIdentifier = currentId; - - /* - * Get the expression to depend on, which may involve PropertyLoads - * for member expressions - */ - let currentDep: - | NodePath - | NodePath - | NodePath = baseIdentifier; - - while (true) { - const nextDep: null | NodePath = currentDep.parentPath; - if ( - nextDep && - nextDep.isMemberExpression() && - isValidDependency(nextDep) - ) { - currentDep = nextDep; - } else { - break; - } - } - - dependency = currentDep; } else { baseIdentifier = path; - dependency = path; } /* * Skip dependency path, as we already tried to recursively add it (+ all subexpressions) * as a dependency. */ - dependency.skip(); + path.skip(); // Add the base identifier binding as a dependency. const binding = baseIdentifier.scope.getBinding(baseIdentifier.node.name); - if (binding === undefined || !pureScopes.has(binding.scope)) { - return; - } - const idKey = String(addCapturedId(binding.identifier)); - - // Add the expression (potentially a memberexpr path) as a dependency. - let exprKey = idKey; - if (dependency.isMemberExpression()) { - let pathTokens = []; - let current: NodePath = dependency; - while (current.isMemberExpression()) { - const property = current.get('property') as NodePath; - pathTokens.push(property.node.name); - current = current.get('object'); - } - - exprKey += '.' + pathTokens.reverse().join('.'); - } else if (dependency.isJSXMemberExpression()) { - let pathTokens = []; - let current: NodePath = - dependency; - while (current.isJSXMemberExpression()) { - const property = current.get('property'); - pathTokens.push(property.node.name); - current = current.get('object'); - } - } - - if (!seenPaths.has(exprKey)) { - let loweredDep: Place; - if (dependency.isJSXIdentifier()) { - loweredDep = lowerValueToTemporary(builder, { - kind: 'LoadLocal', - place: lowerIdentifier(builder, dependency), - loc: path.node.loc ?? GeneratedSource, - }); - } else if (dependency.isJSXMemberExpression()) { - loweredDep = lowerJsxMemberExpression(builder, dependency); - } else { - loweredDep = lowerExpressionToTemporary(builder, dependency); - } - capturedRefs.add(loweredDep); - seenPaths.add(exprKey); + if (binding !== undefined && pureScopes.has(binding.scope)) { + capturedIds.add(binding.identifier); } } @@ -4305,13 +4175,13 @@ function gatherCapturedDeps( return; } else if (path.isJSXElement()) { handleMaybeDependency(path.get('openingElement')); - } else if (path.isMemberExpression() || path.isIdentifier()) { + } else if (path.isIdentifier()) { handleMaybeDependency(path); } }, }); - return {identifiers: [...capturedIds.keys()], refs: [...capturedRefs]}; + return [...capturedIds.keys()]; } function notNull(value: T | null): value is T { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index d3c919a6d8..a422570fff 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -131,15 +131,7 @@ function collectHoistablePropertyLoadsImpl( fn: HIRFunction, context: CollectHoistablePropertyLoadsContext, ): ReadonlyMap { - const functionExpressionLoads = collectFunctionExpressionFakeLoads(fn); - const actuallyEvaluatedTemporaries = new Map( - [...context.temporaries].filter(([id]) => !functionExpressionLoads.has(id)), - ); - - const nodes = collectNonNullsInBlocks(fn, { - ...context, - temporaries: actuallyEvaluatedTemporaries, - }); + const nodes = collectNonNullsInBlocks(fn, context); propagateNonNull(fn, nodes, context.registry); if (DEBUG_PRINT) { @@ -598,30 +590,3 @@ function reduceMaybeOptionalChains( } } while (changed); } - -function collectFunctionExpressionFakeLoads( - fn: HIRFunction, -): Set { - const sources = new Map(); - const functionExpressionReferences = new Set(); - - for (const [_, block] of fn.body.blocks) { - for (const {lvalue, value} of block.instructions) { - if ( - value.kind === 'FunctionExpression' || - value.kind === 'ObjectMethod' - ) { - for (const reference of value.loweredFunc.dependencies) { - let curr: IdentifierId | undefined = reference.identifier.id; - while (curr != null) { - functionExpressionReferences.add(curr); - curr = sources.get(curr); - } - } - } else if (value.kind === 'PropertyLoad') { - sources.set(lvalue.identifier.id, value.object.identifier.id); - } - } - } - return functionExpressionReferences; -} diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 113af2025d..8de9218a66 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -245,8 +245,6 @@ const EnvironmentConfigSchema = z.object({ */ enableUseTypeAnnotations: z.boolean().default(false), - enableFunctionDependencyRewrite: z.boolean().default(true), - /** * Enables inference of optional dependency chains. Without this flag * a property chain such as `props?.items?.foo` will infer as a dep on diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index a6a9cbcd48..4df6da6c17 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -722,7 +722,6 @@ export type ObjectProperty = { }; export type LoweredFunction = { - dependencies: Array; func: HIRFunction; }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeOverlappingReactiveScopesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeOverlappingReactiveScopesHIR.ts index a3740539b2..5b286e917d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeOverlappingReactiveScopesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeOverlappingReactiveScopesHIR.ts @@ -148,6 +148,14 @@ function collectScopeInfo(fn: HIRFunction): ScopeInfo { const scope = place.identifier.scope; if (scope != null) { placeScopes.set(place, scope); + /** + * Record both mutating and non-mutating scopes to merge scopes with + * still-mutating values with inner scopes that alias those values + * (see `nonmutating-capture-in-unsplittable-memo-block`) + * + * Note that this isn't perfect, as it also leads to merging of mutating + * scopes with JSX single-instruction scopes (see `mutation-within-jsx`) + */ if (scope.range.start !== scope.range.end) { getOrInsertDefault(scopeStarts, scope.range.start, new Set()).add( scope, @@ -254,7 +262,7 @@ function visitPlace( * of the stack to the mutated outer scope. */ const placeScope = getPlaceScope(id, place); - if (placeScope != null && isMutable({id} as any, place)) { + if (placeScope != null && isMutable({id}, place)) { const placeScopeIdx = activeScopes.indexOf(placeScope); if (placeScopeIdx !== -1 && placeScopeIdx !== activeScopes.length - 1) { joined.union([placeScope, ...activeScopes.slice(placeScopeIdx + 1)]); @@ -275,6 +283,13 @@ function getOverlappingReactiveScopes( for (const instr of block.instructions) { visitInstructionId(instr.id, context, state); for (const place of eachInstructionOperand(instr)) { + if ( + (instr.value.kind === 'FunctionExpression' || + instr.value.kind === 'ObjectMethod') && + place.identifier.type.kind === 'Primitive' + ) { + continue; + } visitPlace(instr.id, place, state); } for (const place of eachInstructionLValue(instr)) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts index a6f6c606e1..7a6586730f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts @@ -538,9 +538,6 @@ export function printInstructionValue(instrValue: ReactiveValue): string { .split('\n') .map(line => ` ${line}`) .join('\n'); - const deps = instrValue.loweredFunc.dependencies - .map(dep => printPlace(dep)) - .join(','); const context = instrValue.loweredFunc.func.context .map(dep => printPlace(dep)) .join(','); @@ -557,7 +554,7 @@ export function printInstructionValue(instrValue: ReactiveValue): string { }) .join(', ') ?? ''; const type = printType(instrValue.loweredFunc.func.returnType).trim(); - value = `${kind} ${name} @deps[${deps}] @context[${context}] @effects[${effects}]${type !== '' ? ` return${type}` : ''}:\n${fn}`; + value = `${kind} ${name} @context[${context}] @effects[${effects}]${type !== '' ? ` return${type}` : ''}:\n${fn}`; break; } case 'TaggedTemplateExpression': { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts index 08856e9143..4cb84870a8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts @@ -738,9 +738,8 @@ function collectDependencies( } for (const instr of block.instructions) { if ( - fn.env.config.enableFunctionDependencyRewrite && - (instr.value.kind === 'FunctionExpression' || - instr.value.kind === 'ObjectMethod') + instr.value.kind === 'FunctionExpression' || + instr.value.kind === 'ObjectMethod' ) { context.declare(instr.lvalue.identifier, { id: instr.id, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts index c9ee803bfa..49ff3c256e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts @@ -193,7 +193,7 @@ export function* eachInstructionValueOperand( } case 'ObjectMethod': case 'FunctionExpression': { - yield* instrValue.loweredFunc.dependencies; + yield* instrValue.loweredFunc.func.context; break; } case 'TaggedTemplateExpression': { @@ -517,8 +517,9 @@ export function mapInstructionValueOperands( } case 'ObjectMethod': case 'FunctionExpression': { - instrValue.loweredFunc.dependencies = - instrValue.loweredFunc.dependencies.map(d => fn(d)); + instrValue.loweredFunc.func.context = + instrValue.loweredFunc.func.context.map(d => fn(d)); + break; } case 'TaggedTemplateExpression': { diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts index 75bd8f6811..5381262874 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts @@ -10,9 +10,8 @@ import { Effect, HIRFunction, Identifier, - IdentifierName, + IdentifierId, LoweredFunction, - Place, isRefOrRefValue, makeInstructionId, } from '../HIR'; @@ -23,78 +22,39 @@ import {inferMutableContextVariables} from './InferMutableContextVariables'; import {inferMutableRanges} from './InferMutableRanges'; import inferReferenceEffects from './InferReferenceEffects'; -type Dependency = { - identifier: Identifier; - path: Array; -}; - // Helper class to track indirections such as LoadLocal and PropertyLoad. export class IdentifierState { - properties: Map = new Map(); + properties: Map = new Map(); resolve(identifier: Identifier): Identifier { - const resolved = this.properties.get(identifier); + const resolved = this.properties.get(identifier.id); if (resolved !== undefined) { - return resolved.identifier; + return resolved; } return identifier; } - declareProperty(lvalue: Place, object: Place, property: string): void { - const objectDependency = this.properties.get(object.identifier); - let nextDependency: Dependency; - if (objectDependency === undefined) { - nextDependency = {identifier: object.identifier, path: [property]}; - } else { - nextDependency = { - identifier: objectDependency.identifier, - path: [...objectDependency.path, property], - }; - } - this.properties.set(lvalue.identifier, nextDependency); - } - - declareTemporary(lvalue: Place, value: Place): void { - const resolved: Dependency = this.properties.get(value.identifier) ?? { - identifier: value.identifier, - path: [], - }; - this.properties.set(lvalue.identifier, resolved); + alias(lvalue: Identifier, value: Identifier): void { + this.properties.set(lvalue.id, this.properties.get(value.id) ?? value); } } export default function analyseFunctions(func: HIRFunction): void { - const state = new IdentifierState(); - for (const [_, block] of func.body.blocks) { for (const instr of block.instructions) { switch (instr.value.kind) { case 'ObjectMethod': case 'FunctionExpression': { lower(instr.value.loweredFunc.func); - infer(instr.value.loweredFunc, state, func.context); - break; - } - case 'PropertyLoad': { - state.declareProperty( - instr.lvalue, - instr.value.object, - instr.value.property, - ); - break; - } - case 'ComputedLoad': { - /* - * The path is set to an empty string as the path doesn't really - * matter for a computed load. + infer(instr.value.loweredFunc); + + /** + * Reset mutable range for outer inferReferenceEffects */ - state.declareProperty(instr.lvalue, instr.value.object, ''); - break; - } - case 'LoadLocal': - case 'LoadContext': { - if (instr.lvalue.identifier.name === null) { - state.declareTemporary(instr.lvalue, instr.value.place); + for (const operand of instr.value.loweredFunc.func.context) { + operand.identifier.mutableRange.start = makeInstructionId(0); + operand.identifier.mutableRange.end = makeInstructionId(0); + operand.identifier.scope = null; } break; } @@ -110,7 +70,6 @@ function lower(func: HIRFunction): void { inferMutableRanges(func); rewriteInstructionKindsBasedOnReassignment(func); inferReactiveScopeVariables(func); - inferMutableContextVariables(func); func.env.logger?.debugLogIRs?.({ kind: 'hir', name: 'AnalyseFunction (inner)', @@ -118,32 +77,16 @@ function lower(func: HIRFunction): void { }); } -function infer( - loweredFunc: LoweredFunction, - state: IdentifierState, - context: Array, -): void { - const mutations = new Map(); +function infer(loweredFunc: LoweredFunction): void { + const knownMutated = inferMutableContextVariables(loweredFunc.func); for (const operand of loweredFunc.func.context) { - if ( - isMutatedOrReassigned(operand.identifier) && - operand.identifier.name !== null - ) { - mutations.set(operand.identifier.name.value, operand.effect); - } - } - - for (const dep of loweredFunc.dependencies) { - let name: IdentifierName | null = null; - - if (state.properties.has(dep.identifier)) { - const receiver = state.properties.get(dep.identifier)!; - name = receiver.identifier.name; - } else { - name = dep.identifier.name; - } - - if (isRefOrRefValue(dep.identifier)) { + const identifier = operand.identifier; + CompilerError.invariant(operand.effect === Effect.Unknown, { + reason: + '[AnalyseFunctions] Expected Function context effects to not have been set', + loc: operand.loc, + }); + if (isRefOrRefValue(identifier)) { /* * TODO: this is a hack to ensure we treat functions which reference refs * as having a capture and therefore being considered mutable. this ensures @@ -151,43 +94,16 @@ function infer( * could be called, and allows us to help ensure it isn't called during * render */ - dep.effect = Effect.Capture; - } else if (name !== null) { - const effect = mutations.get(name.value); - if (effect !== undefined) { - dep.effect = effect === Effect.Unknown ? Effect.Capture : effect; - } + operand.effect = Effect.Capture; + } else if (knownMutated.has(operand)) { + operand.effect = Effect.Mutate; + } else if (isMutatedOrReassigned(identifier)) { + // Note that this also reflects if identifier is ConditionallyMutated + operand.effect = Effect.Capture; + } else { + operand.effect = Effect.Read; } } - - /* - * This could potentially add duplicate deps to mutatedDeps in the case of - * mutating a context ref in the child function and in this parent function. - * It might be useful to dedupe this. - * - * In practice this never really matters because the Component function has no - * context refs, so it will never have duplicate deps. - */ - for (const place of context) { - CompilerError.invariant(place.identifier.name !== null, { - reason: 'context refs should always have a name', - description: null, - loc: place.loc, - suggestions: null, - }); - - const effect = mutations.get(place.identifier.name.value); - if (effect !== undefined) { - place.effect = effect === Effect.Unknown ? Effect.Capture : effect; - loweredFunc.dependencies.push(place); - } - } - - for (const operand of loweredFunc.func.context) { - operand.identifier.mutableRange.start = makeInstructionId(0); - operand.identifier.mutableRange.end = makeInstructionId(0); - operand.identifier.scope = null; - } } function isMutatedOrReassigned(id: Identifier): boolean { diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableContextVariables.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableContextVariables.ts index 67babf43db..0025472721 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableContextVariables.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableContextVariables.ts @@ -55,32 +55,21 @@ import {IdentifierState} from './AnalyseFunctions'; * fn(); * ``` */ -export function inferMutableContextVariables(fn: HIRFunction): void { +export function inferMutableContextVariables(fn: HIRFunction): Set { const state = new IdentifierState(); const knownMutatedIdentifiers = new Set(); for (const [, block] of fn.body.blocks) { for (const instr of block.instructions) { switch (instr.value.kind) { - case 'PropertyLoad': { - state.declareProperty( - instr.lvalue, - instr.value.object, - instr.value.property, - ); - break; - } + case 'PropertyLoad': case 'ComputedLoad': { - /* - * The path is set to an empty string as the path doesn't really - * matter for a computed load. - */ - state.declareProperty(instr.lvalue, instr.value.object, ''); + state.alias(instr.lvalue.identifier, instr.value.object.identifier); break; } case 'LoadLocal': case 'LoadContext': { if (instr.lvalue.identifier.name === null) { - state.declareTemporary(instr.lvalue, instr.value.place); + state.alias(instr.lvalue.identifier, instr.value.place.identifier); } break; } @@ -95,11 +84,13 @@ export function inferMutableContextVariables(fn: HIRFunction): void { visitOperand(state, knownMutatedIdentifiers, operand); } } + const results = new Set(); for (const operand of fn.context) { if (knownMutatedIdentifiers.has(operand.identifier)) { - operand.effect = Effect.Mutate; + results.add(operand); } } + return results; } function visitOperand( diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts index 0afe479df0..6420e74a2f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts @@ -390,29 +390,31 @@ class InferenceState { freezeValues(values: Set, reason: Set): void { for (const value of values) { + if (value.kind === 'DeclareContext') { + /** + * Avoid freezing hoisted context declarations + * function Component() { + * const cb = useBar(() => foo(2)); // produces a hoisted context declaration + * const foo = useFoo(); // reassigns to the context variable + * return ; + * } + */ + continue; + } this.#values.set(value, { kind: ValueKind.Frozen, reason, context: new Set(), }); - if (value.kind === 'FunctionExpression') { - if ( - this.#env.config.enablePreserveExistingMemoizationGuarantees || - this.#env.config.enableTransitivelyFreezeFunctionExpressions - ) { - if (value.kind === 'FunctionExpression') { - /* - * We want to freeze the captured values, not mark the operands - * themselves as frozen. There could be mutations that occur - * before the freeze we are processing, and it would be invalid - * to overwrite those mutations as a freeze. - */ - for (const operand of eachInstructionValueOperand(value)) { - const operandValues = this.#variables.get(operand.identifier.id); - if (operandValues !== undefined) { - this.freezeValues(operandValues, reason); - } - } + if ( + value.kind === 'FunctionExpression' && + (this.#env.config.enablePreserveExistingMemoizationGuarantees || + this.#env.config.enableTransitivelyFreezeFunctionExpressions) + ) { + for (const operand of value.loweredFunc.func.context) { + const operandValues = this.#variables.get(operand.identifier.id); + if (operandValues !== undefined) { + this.freezeValues(operandValues, reason); } } } @@ -1143,17 +1145,17 @@ function inferBlock( case 'ObjectMethod': case 'FunctionExpression': { let hasMutableOperand = false; - const mutableOperands: Array = []; for (const operand of eachInstructionOperand(instr)) { + CompilerError.invariant(operand.effect !== Effect.Unknown, { + reason: 'Expected fn effects to be populated', + loc: operand.loc, + }); state.referenceAndRecordEffects( freezeActions, operand, - operand.effect === Effect.Unknown ? Effect.Read : operand.effect, + operand.effect, ValueReason.Other, ); - if (isMutableEffect(operand.effect, operand.loc)) { - mutableOperands.push(operand); - } hasMutableOperand ||= isMutableEffect(operand.effect, operand.loc); } /* diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts index e27b8f9521..5b700b23b4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts @@ -270,7 +270,6 @@ function emitSelectorFn(env: Environment, keys: Array): Instruction { name: null, loweredFunc: { func: fn, - dependencies: [], }, type: 'ArrowFunctionExpression', loc: GeneratedSource, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts index 7a1473be40..0e6d1fd592 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions.ts @@ -24,7 +24,6 @@ export function outlineFunctions( } if ( value.kind === 'FunctionExpression' && - value.loweredFunc.dependencies.length === 0 && value.loweredFunc.func.context.length === 0 && // TODO: handle outlining named functions value.loweredFunc.func.id === null && diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts index 1108422f07..1f104d8592 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts @@ -379,6 +379,14 @@ export function findDisjointMutableValues( */ operand.identifier.mutableRange.start > 0 ) { + if ( + instr.value.kind === 'FunctionExpression' || + instr.value.kind === 'ObjectMethod' + ) { + if (operand.identifier.type.kind === 'Primitive') { + continue; + } + } operands.push(operand.identifier); } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts b/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts index bae038f9bd..12c8c0e2e6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts @@ -13,6 +13,8 @@ import { eachTerminalOperand, } from '../HIR/visitors'; +const DEBUG = false; + /* * Pass to eliminate redundant phi nodes: * - all operands are the same identifier, ie `x2 = phi(x1, x1, x1)`. @@ -141,6 +143,23 @@ export function eliminateRedundantPhi( * have already propagated forwards since we visit in reverse postorder. */ } while (rewrites.size > size && hasBackEdge); + + if (DEBUG) { + for (const [, block] of ir.blocks) { + for (const phi of block.phis) { + CompilerError.invariant(!rewrites.has(phi.place.identifier), { + reason: '[EliminateRedundantPhis]: rewrite not complete', + loc: phi.place.loc, + }); + for (const [, operand] of phi.operands) { + CompilerError.invariant(!rewrites.has(operand.identifier), { + reason: '[EliminateRedundantPhis]: rewrite not complete', + loc: phi.place.loc, + }); + } + } + } + } } function rewritePlace( diff --git a/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts b/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts index caba0d3c36..820f7388dc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts @@ -301,9 +301,6 @@ function enterSSAImpl( entry.preds.add(blockId); builder.defineFunction(loweredFunc); builder.enter(() => { - loweredFunc.context = loweredFunc.context.map(p => - builder.getPlace(p), - ); loweredFunc.params = loweredFunc.params.map(param => { if (param.kind === 'Identifier') { return builder.definePlace(param); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts b/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts index a35c4ddb01..a480b5d7c7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts @@ -319,51 +319,6 @@ function visitFunctionExpressionAndPropagateFireDependencies( replaceFireFunctions(fnExpr.loweredFunc.func, context), ); - /* - * Make a mapping from each dependency to the corresponding LoadLocal for it so that - * we can replace the loaded place with the generated fire function binding - */ - const loadLocalsToDepLoads = new Map(); - for (const dep of fnExpr.loweredFunc.dependencies) { - const loadLocal = context.getLoadLocalInstr(dep.identifier.id); - if (loadLocal != null) { - loadLocalsToDepLoads.set(loadLocal.place.identifier.id, loadLocal); - } - } - - const replacedCallees = new Map(); - for (const [ - calleeIdentifierId, - loadedFireFunctionBindingPlace, - ] of calleesCapturedByFnExpression.entries()) { - /* - * Given the ids of captured fire callees, look at the deps for loads of those identifiers - * and replace them with the new fire function binding - */ - const loadLocal = loadLocalsToDepLoads.get(calleeIdentifierId); - if (loadLocal == null) { - context.pushError({ - loc: fnExpr.loc, - description: null, - severity: ErrorSeverity.Invariant, - reason: - '[InsertFire] No loadLocal found for fire call argument for lambda', - suggestions: null, - }); - continue; - } - - const oldPlaceId = loadLocal.place.identifier.id; - loadLocal.place = { - ...loadedFireFunctionBindingPlace.fireFunctionBinding, - }; - - replacedCallees.set( - oldPlaceId, - loadedFireFunctionBindingPlace.fireFunctionBinding, - ); - } - // For each replaced callee, update the context of the function expression to track it for ( let contextIdx = 0; @@ -371,9 +326,13 @@ function visitFunctionExpressionAndPropagateFireDependencies( contextIdx++ ) { const contextItem = fnExpr.loweredFunc.func.context[contextIdx]; - const replacedCallee = replacedCallees.get(contextItem.identifier.id); + const replacedCallee = calleesCapturedByFnExpression.get( + contextItem.identifier.id, + ); if (replacedCallee != null) { - fnExpr.loweredFunc.func.context[contextIdx] = replacedCallee; + fnExpr.loweredFunc.func.context[contextIdx] = { + ...replacedCallee.fireFunctionBinding, + }; } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-fn-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-fn-expr.expect.md new file mode 100644 index 0000000000..b30ee7e0d6 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-fn-expr.expect.md @@ -0,0 +1,120 @@ + +## Input + +```javascript +// @enableTransitivelyFreezeFunctionExpressions:false +import { + Stringify, + mutate, + identity, + setPropertyByKey, + shallowCopy, +} from 'shared-runtime'; +/** + * Function expression version of `aliased-nested-scope-truncated-dep`. + * + * In this fixture, the output would be invalid if propagateScopeDeps did not + * avoid adding MemberExpression dependencies which would other evaluate during + * the mutable ranges of their base objects. + * This is different from `aliased-nested-scope-truncated-dep` which *does* + * produce correct output regardless of MemberExpression dependency truncation. + * + * Note while other expressions evaluate inline, function expressions *always* + * represent deferred evaluation. This means that + * (1) it's always safe to reorder function expression creation until its + * earliest potential invocation + * (2) it's invalid to eagerly evaluate function expression dependencies during + * their respective mutable ranges. + */ + +function Component({prop}) { + let obj = shallowCopy(prop); + + const aliasedObj = identity(obj); + + // When `obj` is mutable (either directly or through aliases), taking a + // dependency on `obj.id` is invalid as it may change before getId() is invoked + const getId = () => obj.id; + + mutate(aliasedObj); + setPropertyByKey(aliasedObj, 'id', prop.id + 1); + + // Calling getId() should return prop.id + 1, not the prev + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{prop: {id: 1}}], + sequentialRenders: [{prop: {id: 1}}, {prop: {id: 1}}, {prop: {id: 2}}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enableTransitivelyFreezeFunctionExpressions:false +import { + Stringify, + mutate, + identity, + setPropertyByKey, + shallowCopy, +} from "shared-runtime"; +/** + * Function expression version of `aliased-nested-scope-truncated-dep`. + * + * In this fixture, the output would be invalid if propagateScopeDeps did not + * avoid adding MemberExpression dependencies which would other evaluate during + * the mutable ranges of their base objects. + * This is different from `aliased-nested-scope-truncated-dep` which *does* + * produce correct output regardless of MemberExpression dependency truncation. + * + * Note while other expressions evaluate inline, function expressions *always* + * represent deferred evaluation. This means that + * (1) it's always safe to reorder function expression creation until its + * earliest potential invocation + * (2) it's invalid to eagerly evaluate function expression dependencies during + * their respective mutable ranges. + */ + +function Component(t0) { + const $ = _c(2); + const { prop } = t0; + let t1; + if ($[0] !== prop) { + const obj = shallowCopy(prop); + + const aliasedObj = identity(obj); + + const getId = () => obj.id; + + mutate(aliasedObj); + setPropertyByKey(aliasedObj, "id", prop.id + 1); + + t1 = ; + $[0] = prop; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ prop: { id: 1 } }], + sequentialRenders: [ + { prop: { id: 1 } }, + { prop: { id: 1 } }, + { prop: { id: 2 } }, + ], +}; + +``` + +### Eval output +(kind: ok)
{"getId":{"kind":"Function","result":2},"shouldInvokeFns":true}
+
{"getId":{"kind":"Function","result":2},"shouldInvokeFns":true}
+
{"getId":{"kind":"Function","result":3},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-fn-expr.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-fn-expr.tsx new file mode 100644 index 0000000000..40022c6f65 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-fn-expr.tsx @@ -0,0 +1,46 @@ +// @enableTransitivelyFreezeFunctionExpressions:false +import { + Stringify, + mutate, + identity, + setPropertyByKey, + shallowCopy, +} from 'shared-runtime'; +/** + * Function expression version of `aliased-nested-scope-truncated-dep`. + * + * In this fixture, the output would be invalid if propagateScopeDeps did not + * avoid adding MemberExpression dependencies which would other evaluate during + * the mutable ranges of their base objects. + * This is different from `aliased-nested-scope-truncated-dep` which *does* + * produce correct output regardless of MemberExpression dependency truncation. + * + * Note while other expressions evaluate inline, function expressions *always* + * represent deferred evaluation. This means that + * (1) it's always safe to reorder function expression creation until its + * earliest potential invocation + * (2) it's invalid to eagerly evaluate function expression dependencies during + * their respective mutable ranges. + */ + +function Component({prop}) { + let obj = shallowCopy(prop); + + const aliasedObj = identity(obj); + + // When `obj` is mutable (either directly or through aliases), taking a + // dependency on `obj.id` is invalid as it may change before getId() is invoked + const getId = () => obj.id; + + mutate(aliasedObj); + setPropertyByKey(aliasedObj, 'id', prop.id + 1); + + // Calling getId() should return prop.id + 1, not the prev + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{prop: {id: 1}}], + sequentialRenders: [{prop: {id: 1}}, {prop: {id: 1}}, {prop: {id: 2}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.expect.md new file mode 100644 index 0000000000..933fafff5f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.expect.md @@ -0,0 +1,221 @@ + +## Input + +```javascript +import { + Stringify, + mutate, + identity, + shallowCopy, + setPropertyByKey, +} from 'shared-runtime'; + +/** + * This fixture is similar to `bug-aliased-capture-aliased-mutate` and + * `nonmutating-capture-in-unsplittable-memo-block`, but with a focus on + * dependency extraction. + * + * NOTE: this fixture is currently valid, but will break with optimizations: + * - Scope and mutable-range based reordering may move the array creation + * *after* the `mutate(aliasedObj)` call. This is invalid if mutate + * reassigns inner properties. + * - RecycleInto or other deeper-equality optimizations may produce invalid + * output -- it may compare the array's contents / dependencies too early. + * - Runtime validation for immutable values will break if `mutate` does + * interior mutation of the value captured into the array. + * + * Before scope block creation, HIR looks like this: + * // + * // $1 is unscoped as obj's mutable range will be + * // extended in a later pass + * // + * $1 = LoadLocal obj@0[0:12] + * $2 = PropertyLoad $1.id + * // + * // $3 gets assigned a scope as Array is an allocating + * // instruction, but this does *not* get extended or + * // merged into the later mutation site. + * // (explained in `bug-aliased-capture-aliased-mutate`) + * // + * $3@1 = Array[$2] + * ... + * $10@0 = LoadLocal shallowCopy@0[0, 12] + * $11 = LoadGlobal mutate + * $12 = $11($10@0[0, 12]) + * + * When filling in scope dependencies, we find that it's incorrect to depend on + * PropertyLoads from obj as it hasn't completed its mutable range. Following + * the immutable / mutable-new typing system, we check the identity of obj to + * detect whether it was newly created (and thus mutable) in this render pass. + * + * HIR with scopes looks like this. + * bb0: + * $1 = LoadLocal obj@0[0:12] + * $2 = PropertyLoad $1.id + * scopeTerminal deps=[obj@0] block=bb1 fallt=bb2 + * bb1: + * $3@1 = Array[$2] + * goto bb2 + * bb2: + * ... + * + * This is surprising as deps now is entirely decoupled from temporaries used + * by the block itself. scope @1's instructions now reference a value (1) + * produced outside its scope range and (2) not represented in its dependencies + * + * The right thing to do is to ensure that all Loads from a value get assigned + * the value's reactive scope. This also requires track mutating and aliasing + * separately from scope range. In this example, that would correctly merge + * the scopes of $3 with obj. + * Runtime validation and optimizations such as ReactiveGraph-based reordering + * require this as well. + * + * A tempting fix is to instead extend $3's ReactiveScope range up to include + * $2 (the PropertyLoad). This fixes dependency deduping but not reordering + * and mutability. + */ +function Component({prop}) { + let obj = shallowCopy(prop); + const aliasedObj = identity(obj); + + // [obj.id] currently is assigned its own reactive scope + const id = [obj.id]; + + // Writing to the alias may reassign to previously captured references. + // The compiler currently produces valid output, but this breaks with + // reordering, recycleInto, and other potential optimizations. + mutate(aliasedObj); + setPropertyByKey(aliasedObj, 'id', prop.id + 1); + + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{prop: {id: 1}}], + sequentialRenders: [{prop: {id: 1}}, {prop: {id: 1}}, {prop: {id: 2}}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { + Stringify, + mutate, + identity, + shallowCopy, + setPropertyByKey, +} from "shared-runtime"; + +/** + * This fixture is similar to `bug-aliased-capture-aliased-mutate` and + * `nonmutating-capture-in-unsplittable-memo-block`, but with a focus on + * dependency extraction. + * + * NOTE: this fixture is currently valid, but will break with optimizations: + * - Scope and mutable-range based reordering may move the array creation + * *after* the `mutate(aliasedObj)` call. This is invalid if mutate + * reassigns inner properties. + * - RecycleInto or other deeper-equality optimizations may produce invalid + * output -- it may compare the array's contents / dependencies too early. + * - Runtime validation for immutable values will break if `mutate` does + * interior mutation of the value captured into the array. + * + * Before scope block creation, HIR looks like this: + * // + * // $1 is unscoped as obj's mutable range will be + * // extended in a later pass + * // + * $1 = LoadLocal obj@0[0:12] + * $2 = PropertyLoad $1.id + * // + * // $3 gets assigned a scope as Array is an allocating + * // instruction, but this does *not* get extended or + * // merged into the later mutation site. + * // (explained in `bug-aliased-capture-aliased-mutate`) + * // + * $3@1 = Array[$2] + * ... + * $10@0 = LoadLocal shallowCopy@0[0, 12] + * $11 = LoadGlobal mutate + * $12 = $11($10@0[0, 12]) + * + * When filling in scope dependencies, we find that it's incorrect to depend on + * PropertyLoads from obj as it hasn't completed its mutable range. Following + * the immutable / mutable-new typing system, we check the identity of obj to + * detect whether it was newly created (and thus mutable) in this render pass. + * + * HIR with scopes looks like this. + * bb0: + * $1 = LoadLocal obj@0[0:12] + * $2 = PropertyLoad $1.id + * scopeTerminal deps=[obj@0] block=bb1 fallt=bb2 + * bb1: + * $3@1 = Array[$2] + * goto bb2 + * bb2: + * ... + * + * This is surprising as deps now is entirely decoupled from temporaries used + * by the block itself. scope @1's instructions now reference a value (1) + * produced outside its scope range and (2) not represented in its dependencies + * + * The right thing to do is to ensure that all Loads from a value get assigned + * the value's reactive scope. This also requires track mutating and aliasing + * separately from scope range. In this example, that would correctly merge + * the scopes of $3 with obj. + * Runtime validation and optimizations such as ReactiveGraph-based reordering + * require this as well. + * + * A tempting fix is to instead extend $3's ReactiveScope range up to include + * $2 (the PropertyLoad). This fixes dependency deduping but not reordering + * and mutability. + */ +function Component(t0) { + const $ = _c(4); + const { prop } = t0; + let t1; + if ($[0] !== prop) { + const obj = shallowCopy(prop); + const aliasedObj = identity(obj); + let t2; + if ($[2] !== obj) { + t2 = [obj.id]; + $[2] = obj; + $[3] = t2; + } else { + t2 = $[3]; + } + const id = t2; + + mutate(aliasedObj); + setPropertyByKey(aliasedObj, "id", prop.id + 1); + + t1 = ; + $[0] = prop; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ prop: { id: 1 } }], + sequentialRenders: [ + { prop: { id: 1 } }, + { prop: { id: 1 } }, + { prop: { id: 2 } }, + ], +}; + +``` + +### Eval output +(kind: ok)
{"id":[1]}
+
{"id":[1]}
+
{"id":[2]}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.tsx new file mode 100644 index 0000000000..4d9d7e78fb --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/aliased-nested-scope-truncated-dep.tsx @@ -0,0 +1,93 @@ +import { + Stringify, + mutate, + identity, + shallowCopy, + setPropertyByKey, +} from 'shared-runtime'; + +/** + * This fixture is similar to `bug-aliased-capture-aliased-mutate` and + * `nonmutating-capture-in-unsplittable-memo-block`, but with a focus on + * dependency extraction. + * + * NOTE: this fixture is currently valid, but will break with optimizations: + * - Scope and mutable-range based reordering may move the array creation + * *after* the `mutate(aliasedObj)` call. This is invalid if mutate + * reassigns inner properties. + * - RecycleInto or other deeper-equality optimizations may produce invalid + * output -- it may compare the array's contents / dependencies too early. + * - Runtime validation for immutable values will break if `mutate` does + * interior mutation of the value captured into the array. + * + * Before scope block creation, HIR looks like this: + * // + * // $1 is unscoped as obj's mutable range will be + * // extended in a later pass + * // + * $1 = LoadLocal obj@0[0:12] + * $2 = PropertyLoad $1.id + * // + * // $3 gets assigned a scope as Array is an allocating + * // instruction, but this does *not* get extended or + * // merged into the later mutation site. + * // (explained in `bug-aliased-capture-aliased-mutate`) + * // + * $3@1 = Array[$2] + * ... + * $10@0 = LoadLocal shallowCopy@0[0, 12] + * $11 = LoadGlobal mutate + * $12 = $11($10@0[0, 12]) + * + * When filling in scope dependencies, we find that it's incorrect to depend on + * PropertyLoads from obj as it hasn't completed its mutable range. Following + * the immutable / mutable-new typing system, we check the identity of obj to + * detect whether it was newly created (and thus mutable) in this render pass. + * + * HIR with scopes looks like this. + * bb0: + * $1 = LoadLocal obj@0[0:12] + * $2 = PropertyLoad $1.id + * scopeTerminal deps=[obj@0] block=bb1 fallt=bb2 + * bb1: + * $3@1 = Array[$2] + * goto bb2 + * bb2: + * ... + * + * This is surprising as deps now is entirely decoupled from temporaries used + * by the block itself. scope @1's instructions now reference a value (1) + * produced outside its scope range and (2) not represented in its dependencies + * + * The right thing to do is to ensure that all Loads from a value get assigned + * the value's reactive scope. This also requires track mutating and aliasing + * separately from scope range. In this example, that would correctly merge + * the scopes of $3 with obj. + * Runtime validation and optimizations such as ReactiveGraph-based reordering + * require this as well. + * + * A tempting fix is to instead extend $3's ReactiveScope range up to include + * $2 (the PropertyLoad). This fixes dependency deduping but not reordering + * and mutability. + */ +function Component({prop}) { + let obj = shallowCopy(prop); + const aliasedObj = identity(obj); + + // [obj.id] currently is assigned its own reactive scope + const id = [obj.id]; + + // Writing to the alias may reassign to previously captured references. + // The compiler currently produces valid output, but this breaks with + // reordering, recycleInto, and other potential optimizations. + mutate(aliasedObj); + setPropertyByKey(aliasedObj, 'id', prop.id + 1); + + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{prop: {id: 1}}], + sequentialRenders: [{prop: {id: 1}}, {prop: {id: 1}}, {prop: {id: 2}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-access-in-unused-callback-nested.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-access-in-unused-callback-nested.expect.md index 37a510b8c2..3584faf699 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-access-in-unused-callback-nested.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-access-in-unused-callback-nested.expect.md @@ -44,48 +44,44 @@ import { c as _c } from "react/compiler-runtime"; // @validateRefAccessDuringRen import { useEffect, useRef, useState } from "react"; function Component() { - const $ = _c(6); + const $ = _c(5); const ref = useRef(null); const [state, setState] = useState(false); let t0; - let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => {}; - - t1 = []; + t0 = []; $[0] = t0; - $[1] = t1; } else { t0 = $[0]; - t1 = $[1]; } - useEffect(t0, t1); + useEffect(_temp, t0); + let t1; let t2; - let t3; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t2 = () => { + if ($[1] === Symbol.for("react.memo_cache_sentinel")) { + t1 = () => { setState(true); }; - t3 = []; + t2 = []; + $[1] = t1; $[2] = t2; - $[3] = t3; } else { + t1 = $[1]; t2 = $[2]; - t3 = $[3]; } - useEffect(t2, t3); + useEffect(t1, t2); - const t4 = String(state); - let t5; - if ($[4] !== t4) { - t5 = ; + const t3 = String(state); + let t4; + if ($[3] !== t3) { + t4 = ; + $[3] = t3; $[4] = t4; - $[5] = t5; } else { - t5 = $[5]; + t4 = $[4]; } - return t5; + return t4; } +function _temp() {} function Child(t0) { const { ref } = t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-mutate-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-mutate-2.expect.md index c071d5d20e..6836544c5d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-mutate-2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-mutate-2.expect.md @@ -27,7 +27,6 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; function component(a, b) { const $ = _c(2); - const y = { b }; let z; if ($[0] !== a) { z = { a }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-no-mutate.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-no-mutate.expect.md index aa32b3260e..14bf94e770 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-no-mutate.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-no-mutate.expect.md @@ -31,12 +31,20 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(t0) { - const $ = _c(3); + const $ = _c(5); const { a, b } = t0; let z; if ($[0] !== a || $[1] !== b) { z = { a }; - const y = { b }; + let t1; + if ($[3] !== b) { + t1 = { b }; + $[3] = b; + $[4] = t1; + } else { + t1 = $[4]; + } + const y = t1; const x = function () { z.a = 2; return Math.max(y.b, 0); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-simple-alias-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-simple-alias-iife.expect.md index 1b91bc1a11..a071dddba6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-simple-alias-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-simple-alias-iife.expect.md @@ -34,7 +34,6 @@ function component(a) { const x = { a }; y = {}; - y; y = x; mutate(y); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-2-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-2-iife.expect.md index f4721a507f..2afc5fd25d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-2-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-2-iife.expect.md @@ -31,7 +31,6 @@ function bar(a) { const x = [a]; y = {}; - y; y = x[0][1]; $[0] = a; $[1] = y; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3-iife.expect.md index 5c0be290a6..3e57b7dc7c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-3-iife.expect.md @@ -37,8 +37,6 @@ function bar(a, b) { let t; t = {}; - y; - t; y = x[0][1]; t = x[1][0]; $[0] = a; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-4-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-4-iife.expect.md index 34b927d91e..22728aaf43 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-4-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-4-iife.expect.md @@ -31,7 +31,6 @@ function bar(a) { const x = [a]; y = {}; - y; y = x[0].a[1]; $[0] = a; $[1] = y; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-iife.expect.md index 0978be54ac..60f829cdc4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-alias-computed-load-iife.expect.md @@ -30,7 +30,6 @@ function bar(a) { const x = [a]; y = {}; - y; y = x[0]; $[0] = a; $[1] = y; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-reference-changes-type.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-reference-changes-type.expect.md index 1bdc1c09a3..299aa5a31d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-reference-changes-type.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-reference-changes-type.expect.md @@ -25,7 +25,6 @@ function component(a) { const x = { a }; y = 1; - y; y = x; mutate(y); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-inline-iife-reassign.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-inline-iife-reassign.expect.md index d17c934b3b..cf85967682 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-inline-iife-reassign.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-inline-iife-reassign.expect.md @@ -38,9 +38,8 @@ function useTest() { const t1 = (w = 42); const t2 = w; - - w; let t3; + w = 999; t3 = 2; t0 = makeArray(t1, t2, t3); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/const-propagation-into-function-expression-global.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/const-propagation-into-function-expression-global.expect.md index e42ea8ce93..04b6c4f17f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/const-propagation-into-function-expression-global.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/const-propagation-into-function-expression-global.expect.md @@ -19,10 +19,10 @@ function foo() { import { c as _c } from "react/compiler-runtime"; function foo() { const $ = _c(1); + + const getJSX = _temp; let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const getJSX = () => ; - t0 = getJSX(); $[0] = t0; } else { @@ -31,6 +31,9 @@ function foo() { const result = t0; return result; } +function _temp() { + return ; +} ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/const-propagation-into-function-expression-primitive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/const-propagation-into-function-expression-primitive.expect.md index 6686c0b530..60fe0808d9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/const-propagation-into-function-expression-primitive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/const-propagation-into-function-expression-primitive.expect.md @@ -23,13 +23,14 @@ export const FIXTURE_ENTRYPOINT = { ```javascript function foo() { - const f = () => { - console.log(42); - }; + const f = _temp; f(); return 42; } +function _temp() { + console.log(42); +} export const FIXTURE_ENTRYPOINT = { fn: foo, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-into-function-expressions.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-into-function-expressions.expect.md index 8ea2190480..8822eddcdb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-into-function-expressions.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/constant-propagation-into-function-expressions.expect.md @@ -18,12 +18,10 @@ function Component(props) { import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(1); + + const onEvent = _temp; let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const onEvent = () => { - console.log(42); - }; - t0 = ; $[0] = t0; } else { @@ -31,6 +29,9 @@ function Component(props) { } return t0; } +function _temp() { + console.log(42); +} ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-as-jsx-element-tag.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-as-jsx-element-tag.expect.md index 3dc0dba27c..da3bb94ed5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-as-jsx-element-tag.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/context-variable-as-jsx-element-tag.expect.md @@ -34,9 +34,8 @@ function Component(props) { let Component; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { Component = Stringify; - - Component; let t0; + t0 = Component; Component = t0; $[0] = Component; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisting-simple-function-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisting-simple-function-declaration.expect.md index 2045ee7901..1ba0d59e17 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisting-simple-function-declaration.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisting-simple-function-declaration.expect.md @@ -24,13 +24,17 @@ export const FIXTURE_ENTRYPOINT = { ## Error ``` + 4 | } 5 | return baz(); // OK: FuncDecls are HoistableDeclarations that have both declaration and value hoisting - 6 | function baz() { +> 6 | function baz() { + | ^^^^^^^^^^^^^^^^ > 7 | return bar(); - | ^^^ Todo: Support functions with unreachable code that may contain hoisted declarations (7:7) - 8 | } + | ^^^^^^^^^^^^^^^^^ +> 8 | } + | ^^^^ Todo: Support functions with unreachable code that may contain hoisted declarations (6:8) 9 | } 10 | + 11 | export const FIXTURE_ENTRYPOINT = { ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-identifier.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-identifier.expect.md new file mode 100644 index 0000000000..7babe57b00 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-identifier.expect.md @@ -0,0 +1,41 @@ + +## Input + +```javascript +// @enableTransitivelyFreezeFunctionExpressions +import {setPropertyByKey, Stringify, useIdentity} from 'shared-runtime'; + +function Foo({count}) { + const x = {value: 0}; + /** + * After this custom hook call, it's no longer valid to mutate x. + */ + const cb = useIdentity(() => { + setPropertyByKey(x, 'value', count); + }); + + x.value += count; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{count: 1}], +}; + +``` + + +## Error + +``` + 11 | }); + 12 | +> 13 | x.value += count; + | ^ InvalidReact: This mutates a variable that React considers immutable (13:13) + 14 | return ; + 15 | } + 16 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-identifier.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-identifier.tsx new file mode 100644 index 0000000000..b71626a435 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-identifier.tsx @@ -0,0 +1,20 @@ +// @enableTransitivelyFreezeFunctionExpressions +import {setPropertyByKey, Stringify, useIdentity} from 'shared-runtime'; + +function Foo({count}) { + const x = {value: 0}; + /** + * After this custom hook call, it's no longer valid to mutate x. + */ + const cb = useIdentity(() => { + setPropertyByKey(x, 'value', count); + }); + + x.value += count; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{count: 1}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-memberexpr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-memberexpr.expect.md new file mode 100644 index 0000000000..fcc47ddc2b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-memberexpr.expect.md @@ -0,0 +1,41 @@ + +## Input + +```javascript +// @enableTransitivelyFreezeFunctionExpressions +import {mutate, Stringify, useIdentity} from 'shared-runtime'; + +function Foo({count}) { + const x = {value: 0}; + /** + * After this custom hook call, it's no longer valid to mutate x. + */ + const cb = useIdentity(() => { + x.value++; + }); + + x.value += count; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{count: 1}], +}; + +``` + + +## Error + +``` + 11 | }); + 12 | +> 13 | x.value += count; + | ^ InvalidReact: This mutates a variable that React considers immutable (13:13) + 14 | return ; + 15 | } + 16 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-memberexpr.jsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-memberexpr.jsx new file mode 100644 index 0000000000..2a94559c1f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-call-freezes-captured-memberexpr.jsx @@ -0,0 +1,20 @@ +// @enableTransitivelyFreezeFunctionExpressions +import {mutate, Stringify, useIdentity} from 'shared-runtime'; + +function Foo({count}) { + const x = {value: 0}; + /** + * After this custom hook call, it's no longer valid to mutate x. + */ + const cb = useIdentity(() => { + x.value++; + }); + + x.value += count; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{count: 1}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md index db3a192eaf..f66b970f00 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md @@ -22,7 +22,7 @@ function Component(props) { 7 | return hasErrors; 8 | } > 9 | return hasErrors(); - | ^^^^^^^^^ Invariant: [hoisting] Expected value for identifier to be initialized. hasErrors_0$16 (9:9) + | ^^^^^^^^^ Invariant: [hoisting] Expected value for identifier to be initialized. hasErrors_0$14 (9:9) 10 | } 11 | ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.expect.md new file mode 100644 index 0000000000..55cab1e9f3 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.expect.md @@ -0,0 +1,81 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees +function useFoo() { + const onClick = response => { + setState(DISABLED_FORM); + }; + + const [state, setState] = useState(); + const handleLogout = useCallback(() => { + setState(DISABLED_FORM); + }, [setState]); + const getComponent = () => { + return handleLogout()} />; + }; + + // this `getComponent` call should not be inferred as mutating setState + return [getComponent(), onClick]; // pass onClick to avoid dce +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees +function useFoo() { + const $ = _c(9); + const onClick = (response) => { + setState(DISABLED_FORM); + }; + + const [, t0] = useState(); + const setState = t0; + let t1; + if ($[0] !== setState) { + t1 = () => { + setState(DISABLED_FORM); + }; + $[0] = setState; + $[1] = t1; + } else { + t1 = $[1]; + } + setState; + const handleLogout = t1; + let t2; + if ($[2] !== handleLogout) { + t2 = () => handleLogout()} />; + $[2] = handleLogout; + $[3] = t2; + } else { + t2 = $[3]; + } + const getComponent = t2; + let t3; + if ($[4] !== getComponent) { + t3 = getComponent(); + $[4] = getComponent; + $[5] = t3; + } else { + t3 = $[5]; + } + let t4; + if ($[6] !== onClick || $[7] !== t3) { + t4 = [t3, onClick]; + $[6] = onClick; + $[7] = t3; + $[8] = t4; + } else { + t4 = $[8]; + } + return t4; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.js new file mode 100644 index 0000000000..4a44679390 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate-captured-indirectly-jsx.js @@ -0,0 +1,17 @@ +// @validatePreserveExistingMemoizationGuarantees +function useFoo() { + const onClick = response => { + setState(DISABLED_FORM); + }; + + const [state, setState] = useState(); + const handleLogout = useCallback(() => { + setState(DISABLED_FORM); + }, [setState]); + const getComponent = () => { + return handleLogout()} />; + }; + + // this `getComponent` call should not be inferred as mutating setState + return [getComponent(), onClick]; // pass onClick to avoid dce +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate.expect.md new file mode 100644 index 0000000000..483d9b1a8e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate.expect.md @@ -0,0 +1,77 @@ + +## Input + +```javascript +import {useEffect, useState} from 'react'; +import {Stringify} from 'shared-runtime'; + +function Foo() { + /** + * Previously, this lowered to + * $1 = LoadContext capture setState + * $2 = FunctionExpression deps=$1 context=setState + * [[ at this point, we freeze the `LoadContext setState` instruction, but it will never be referenced again ]] + * + * Now, this function expression directly references `setState`, which freezes + * the source `DeclareContext HoistedConst setState`. Freezing source identifiers + * (instead of the one level removed `LoadContext`) is more semantically correct + * for everything *other* than hoisted context declarations. + * + * $2 = Function context=setState + */ + useEffect(() => setState(2), []); + + const [state, setState] = useState(0); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{}], + sequentialRenders: [{}, {}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { useEffect, useState } from "react"; +import { Stringify } from "shared-runtime"; + +function Foo() { + const $ = _c(3); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = []; + $[0] = t0; + } else { + t0 = $[0]; + } + useEffect(() => setState(2), t0); + + const [state, t1] = useState(0); + const setState = t1; + let t2; + if ($[1] !== state) { + t2 = ; + $[1] = state; + $[2] = t2; + } else { + t2 = $[2]; + } + return t2; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{}], + sequentialRenders: [{}, {}], +}; + +``` + +### Eval output +(kind: ok)
{"state":2}
+
{"state":2}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate.js new file mode 100644 index 0000000000..7b26c8d086 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-setstate.js @@ -0,0 +1,28 @@ +import {useEffect, useState} from 'react'; +import {Stringify} from 'shared-runtime'; + +function Foo() { + /** + * Previously, this lowered to + * $1 = LoadContext capture setState + * $2 = FunctionExpression deps=$1 context=setState + * [[ at this point, we freeze the `LoadContext setState` instruction, but it will never be referenced again ]] + * + * Now, this function expression directly references `setState`, which freezes + * the source `DeclareContext HoistedConst setState`. Freezing source identifiers + * (instead of the one level removed `LoadContext`) is more semantically correct + * for everything *other* than hoisted context declarations. + * + * $2 = Function context=setState + */ + useEffect(() => setState(2), []); + + const [state, setState] = useState(0); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{}], + sequentialRenders: [{}, {}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-call-freezes-captured-memberexpr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-call-freezes-captured-memberexpr.expect.md new file mode 100644 index 0000000000..957919516d --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-call-freezes-captured-memberexpr.expect.md @@ -0,0 +1,87 @@ + +## Input + +```javascript +import {useIdentity, Stringify, identity} from 'shared-runtime'; + +function Foo({val1}) { + // `x={inner: val1}` should be able to be memoized + const x = {inner: val1}; + + // Any references to `x` after this hook call should be read-only + const cb = useIdentity(() => x.inner); + + // With enableTransitivelyFreezeFunctionExpressions, it's invalid + // to write to `x` after it's been frozen. + // TODO: runtime validation for DX + const copy = identity(x); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{val1: 1}], + sequentialRenders: [{val1: 1}, {val1: 1}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { useIdentity, Stringify, identity } from "shared-runtime"; + +function Foo(t0) { + const $ = _c(9); + const { val1 } = t0; + let t1; + if ($[0] !== val1) { + t1 = { inner: val1 }; + $[0] = val1; + $[1] = t1; + } else { + t1 = $[1]; + } + const x = t1; + let t2; + if ($[2] !== x.inner) { + t2 = () => x.inner; + $[2] = x.inner; + $[3] = t2; + } else { + t2 = $[3]; + } + const cb = useIdentity(t2); + let t3; + if ($[4] !== x) { + t3 = identity(x); + $[4] = x; + $[5] = t3; + } else { + t3 = $[5]; + } + const copy = t3; + let t4; + if ($[6] !== cb || $[7] !== copy) { + t4 = ; + $[6] = cb; + $[7] = copy; + $[8] = t4; + } else { + t4 = $[8]; + } + return t4; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ val1: 1 }], + sequentialRenders: [{ val1: 1 }, { val1: 1 }], +}; + +``` + +### Eval output +(kind: ok)
{"copy":{"inner":1},"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}
+
{"copy":{"inner":1},"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-call-freezes-captured-memberexpr.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-call-freezes-captured-memberexpr.tsx new file mode 100644 index 0000000000..68e8e03437 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-call-freezes-captured-memberexpr.tsx @@ -0,0 +1,21 @@ +import {useIdentity, Stringify, identity} from 'shared-runtime'; + +function Foo({val1}) { + // `x={inner: val1}` should be able to be memoized + const x = {inner: val1}; + + // Any references to `x` after this hook call should be read-only + const cb = useIdentity(() => x.inner); + + // With enableTransitivelyFreezeFunctionExpressions, it's invalid + // to write to `x` after it's been frozen. + // TODO: runtime validation for DX + const copy = identity(x); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{val1: 1}], + sequentialRenders: [{val1: 1}, {val1: 1}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-local-tag-in-lambda.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-local-tag-in-lambda.expect.md index 74e01a72d5..a7d27bc381 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-local-tag-in-lambda.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-local-tag-in-lambda.expect.md @@ -25,10 +25,10 @@ import { c as _c } from "react/compiler-runtime"; import { Stringify } from "shared-runtime"; function useFoo() { const $ = _c(1); + + const callback = _temp; let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const callback = () => ; - t0 = callback(); $[0] = t0; } else { @@ -36,6 +36,9 @@ function useFoo() { } return t0; } +function _temp() { + return ; +} export const FIXTURE_ENTRYPOINT = { fn: useFoo, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-memberexpr-tag-in-lambda.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-memberexpr-tag-in-lambda.expect.md index 22fa3b2e2a..e5ead2479d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-memberexpr-tag-in-lambda.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-memberexpr-tag-in-lambda.expect.md @@ -25,10 +25,10 @@ import { c as _c } from "react/compiler-runtime"; import * as SharedRuntime from "shared-runtime"; function useFoo() { const $ = _c(1); + + const callback = _temp; let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const callback = () => ; - t0 = callback(); $[0] = t0; } else { @@ -36,6 +36,9 @@ function useFoo() { } return t0; } +function _temp() { + return ; +} export const FIXTURE_ENTRYPOINT = { fn: useFoo, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-non-reactive-to-reactive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-non-reactive-to-reactive.expect.md index d34db46d6a..ed0ddda55b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-non-reactive-to-reactive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-non-reactive-to-reactive.expect.md @@ -26,7 +26,6 @@ function f(a) { const $ = _c(4); let x; if ($[0] !== a) { - x; x = { a }; $[0] = a; $[1] = x; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-ref-non-reactive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-ref-non-reactive.expect.md index 2aa5d4d06d..8dc4839085 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-ref-non-reactive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-mutated-ref-non-reactive.expect.md @@ -27,7 +27,6 @@ function f(a) { const $ = _c(2); let x; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - x; x = {}; $[0] = x; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-function-shadowed-identifiers.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-function-shadowed-identifiers.expect.md index 13ba6d1798..3c624de9eb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-function-shadowed-identifiers.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-function-shadowed-identifiers.expect.md @@ -31,7 +31,7 @@ function Component(props) { let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = (e) => { - setX((currentX) => currentX + null); + setX(_temp); }; $[0] = t0; } else { @@ -48,6 +48,9 @@ function Component(props) { } return t1; } +function _temp(currentX) { + return currentX + null; +} export const FIXTURE_ENTRYPOINT = { fn: Component, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-assignment.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-assignment.expect.md index e8a3e2d627..3fffec6a7d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-assignment.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-assignment.expect.md @@ -35,7 +35,6 @@ function useFoo(arr1, arr2) { if ($[0] !== arr1 || $[1] !== arr2) { const x = [arr1]; - y; (y = x.concat(arr2)), y; $[0] = arr1; $[1] = arr2; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rewrite-phis-in-lambda-capture-context.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rewrite-phis-in-lambda-capture-context.expect.md index 2e451d8948..0c66dee6a8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rewrite-phis-in-lambda-capture-context.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rewrite-phis-in-lambda-capture-context.expect.md @@ -22,26 +22,21 @@ function Component() { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; function Component() { - const $ = _c(1); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { - while (bar()) { - if (baz) { - bar(); - } - } - return () => 4; - }; - $[0] = t0; - } else { - t0 = $[0]; - } - const get4 = t0; + const get4 = _temp2; return get4; } +function _temp2() { + while (bar()) { + if (baz) { + bar(); + } + } + return _temp; +} +function _temp() { + return 4; +} ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md index e335273026..6ad460347f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md @@ -85,7 +85,6 @@ function Inner(props) { input = use(FooContext); } - input; input; let t0; let t1; From 70bd31a49ae4452dd13f4653513f2e9b350a1236 Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Tue, 18 Feb 2025 09:16:26 -0700 Subject: [PATCH 09/13] [compiler] Remove redundant InferMutableContextVariables This removes special casing for `PropertyStore` mutability inference within FunctionExpressions. --- .../src/Inference/AnalyseFunctions.ts | 27 +---- .../Inference/InferMutableContextVariables.ts | 105 ------------------ ...mutate-global-in-effect-fixpoint.expect.md | 68 ++++++------ .../allow-mutate-global-in-effect-fixpoint.js | 7 +- .../reanimated-shared-value-writes.expect.md | 23 ++-- 5 files changed, 55 insertions(+), 175 deletions(-) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableContextVariables.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts index 5381262874..a439b4cd01 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts @@ -10,7 +10,6 @@ import { Effect, HIRFunction, Identifier, - IdentifierId, LoweredFunction, isRefOrRefValue, makeInstructionId, @@ -18,27 +17,9 @@ import { import {deadCodeElimination} from '../Optimization'; import {inferReactiveScopeVariables} from '../ReactiveScopes'; import {rewriteInstructionKindsBasedOnReassignment} from '../SSA'; -import {inferMutableContextVariables} from './InferMutableContextVariables'; import {inferMutableRanges} from './InferMutableRanges'; import inferReferenceEffects from './InferReferenceEffects'; -// Helper class to track indirections such as LoadLocal and PropertyLoad. -export class IdentifierState { - properties: Map = new Map(); - - resolve(identifier: Identifier): Identifier { - const resolved = this.properties.get(identifier.id); - if (resolved !== undefined) { - return resolved; - } - return identifier; - } - - alias(lvalue: Identifier, value: Identifier): void { - this.properties.set(lvalue.id, this.properties.get(value.id) ?? value); - } -} - export default function analyseFunctions(func: HIRFunction): void { for (const [_, block] of func.body.blocks) { for (const instr of block.instructions) { @@ -78,7 +59,6 @@ function lower(func: HIRFunction): void { } function infer(loweredFunc: LoweredFunction): void { - const knownMutated = inferMutableContextVariables(loweredFunc.func); for (const operand of loweredFunc.func.context) { const identifier = operand.identifier; CompilerError.invariant(operand.effect === Effect.Unknown, { @@ -95,10 +75,11 @@ function infer(loweredFunc: LoweredFunction): void { * render */ operand.effect = Effect.Capture; - } else if (knownMutated.has(operand)) { - operand.effect = Effect.Mutate; } else if (isMutatedOrReassigned(identifier)) { - // Note that this also reflects if identifier is ConditionallyMutated + /** + * Reflects direct reassignments, PropertyStores, and ConditionallyMutate + * (directly or through maybe-aliases) + */ operand.effect = Effect.Capture; } else { operand.effect = Effect.Read; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableContextVariables.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableContextVariables.ts deleted file mode 100644 index 0025472721..0000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableContextVariables.ts +++ /dev/null @@ -1,105 +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 {Effect, HIRFunction, Identifier, Place} from '../HIR'; -import { - eachInstructionValueOperand, - eachTerminalOperand, -} from '../HIR/visitors'; -import {IdentifierState} from './AnalyseFunctions'; - -/* - * This pass infers which of the given function's context (free) variables - * are definitively mutated by the function. This analysis is *partial*, - * and only annotates provable mutations, and may miss mutations via indirections. - * The intent of this pass is to drive validations, rejecting known-bad code - * while avoiding false negatives, and the inference should *not* be used to - * drive changes in output. - * - * Note that a complete analysis is possible but would have too many false negatives. - * The approach would be to run LeaveSSA and InferReactiveScopeVariables in order to - * find all possible aliases of a context variable which may be mutated. However, this - * can lead to false negatives: - * - * ``` - * const [x, setX] = useState(null); // x is frozen - * const fn = () => { // context=[x] - * const z = {}; // z is mutable - * foo(z, x); // potentially mutate z and x - * z.a = true; // definitively mutate z - * } - * fn(); - * ``` - * - * When we analyze function expressions we assume that context variables are mutable, - * so we assume that `x` is mutable. We infer that `foo(z, x)` could be mutating the - * two variables to alias each other, such that `z.a = true` could be mutating `x`, - * and we would infer that `x` is definitively mutated. Then when we run - * InferReferenceEffects on the outer code we'd reject it, since there is a definitive - * mutation of a frozen value. - * - * Thus the actual implementation looks at only basic aliasing. The above example would - * pass, since z does not directly alias `x`. However, mutations through trivial aliases - * are detected: - * - * ``` - * const [x, setX] = useState(null); // x is frozen - * const fn = () => { // context=[x] - * const z = x; - * z.a = true; // ERROR: mutates x - * } - * fn(); - * ``` - */ -export function inferMutableContextVariables(fn: HIRFunction): Set { - const state = new IdentifierState(); - const knownMutatedIdentifiers = new Set(); - for (const [, block] of fn.body.blocks) { - for (const instr of block.instructions) { - switch (instr.value.kind) { - case 'PropertyLoad': - case 'ComputedLoad': { - state.alias(instr.lvalue.identifier, instr.value.object.identifier); - break; - } - case 'LoadLocal': - case 'LoadContext': { - if (instr.lvalue.identifier.name === null) { - state.alias(instr.lvalue.identifier, instr.value.place.identifier); - } - break; - } - default: { - for (const operand of eachInstructionValueOperand(instr.value)) { - visitOperand(state, knownMutatedIdentifiers, operand); - } - } - } - } - for (const operand of eachTerminalOperand(block.terminal)) { - visitOperand(state, knownMutatedIdentifiers, operand); - } - } - const results = new Set(); - for (const operand of fn.context) { - if (knownMutatedIdentifiers.has(operand.identifier)) { - results.add(operand); - } - } - return results; -} - -function visitOperand( - state: IdentifierState, - knownMutatedIdentifiers: Set, - operand: Place, -): void { - const resolved = state.resolve(operand.identifier); - if (operand.effect === Effect.Mutate || operand.effect === Effect.Store) { - knownMutatedIdentifiers.add(resolved); - } -} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md index 942daec1dd..76e4432fe9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md @@ -19,9 +19,14 @@ function Component() { // capture into a separate variable that is not a context variable. const y = x; + /** + * Note that this fixture currently produces a stale effect closure if `y = x + * = someGlobal` changes between renders. Under current compiler assumptions, + * that would be a rule of react violation. + */ useEffect(() => { y.value = 'hello'; - }, []); + }); useEffect(() => { setState(someGlobal.value); @@ -46,57 +51,50 @@ import { useEffect, useState } from "react"; let someGlobal = { value: null }; function Component() { - const $ = _c(7); + const $ = _c(5); const [state, setState] = useState(someGlobal); - let t0; - let t1; - let t2; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - let x = someGlobal; - while (x == null) { - x = someGlobal; - } - const y = x; - t0 = useEffect; - t1 = () => { + let x = someGlobal; + while (x == null) { + x = someGlobal; + } + + const y = x; + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = () => { y.value = "hello"; }; - t2 = []; $[0] = t0; + } else { + t0 = $[0]; + } + useEffect(t0); + let t1; + let t2; + if ($[1] === Symbol.for("react.memo_cache_sentinel")) { + t1 = () => { + setState(someGlobal.value); + }; + t2 = [someGlobal]; $[1] = t1; $[2] = t2; } else { - t0 = $[0]; t1 = $[1]; t2 = $[2]; } - t0(t1, t2); - let t3; + useEffect(t1, t2); + + const t3 = String(state); let t4; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { - t3 = () => { - setState(someGlobal.value); - }; - t4 = [someGlobal]; + if ($[3] !== t3) { + t4 =
{t3}
; $[3] = t3; $[4] = t4; } else { - t3 = $[3]; t4 = $[4]; } - useEffect(t3, t4); - - const t5 = String(state); - let t6; - if ($[5] !== t5) { - t6 =
{t5}
; - $[5] = t5; - $[6] = t6; - } else { - t6 = $[6]; - } - return t6; + return t4; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.js index 84bd42aaef..6e44adf204 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.js @@ -15,9 +15,14 @@ function Component() { // capture into a separate variable that is not a context variable. const y = x; + /** + * Note that this fixture currently produces a stale effect closure if `y = x + * = someGlobal` changes between renders. Under current compiler assumptions, + * that would be a rule of react violation. + */ useEffect(() => { y.value = 'hello'; - }, []); + }); useEffect(() => { setState(someGlobal.value); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reanimated-shared-value-writes.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reanimated-shared-value-writes.expect.md index 8f808c94b3..0a19a85428 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reanimated-shared-value-writes.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reanimated-shared-value-writes.expect.md @@ -36,21 +36,22 @@ import { useSharedValue } from "react-native-reanimated"; * of render */ function SomeComponent() { - const $ = _c(3); + const $ = _c(2); const sharedVal = useSharedValue(0); - - const T0 = Button; - const t0 = () => (sharedVal.value = Math.random()); - let t1; - if ($[0] !== T0 || $[1] !== t0) { - t1 = ; - $[0] = T0; + let t0; + if ($[0] !== sharedVal) { + t0 = ( +