@samitouri / QOS-React / commits / 5adf40208f

feat(eslint-plugin-react-hooks): convert to typescript and package type declarations (#32240)

<!-- Thanks for submitting a pull request! We appreciate you spending the time to work on these changes. Please provide enough information so that others can review your pull request. The three fields below are mandatory. Before submitting a pull request, please make sure the following is done: 1. Fork [the repository](https://github.com/facebook/react) and create your branch from `main`. 2. Run `yarn` in the repository root. 3. If you've fixed a bug or added code that should be tested, add tests! 4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch TestName` is helpful in development. 5. Run `yarn test --prod` to test in the production environment. It supports the same options as `yarn test`. 6. If you need a debugger, run `yarn test --debug --watch TestName`, open `chrome://inspect`, and press "Inspect". 7. Format your code with [prettier](https://github.com/prettier/prettier) (`yarn prettier`). 8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only check changed files. 9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`). 10. If you haven't already, complete the CLA. Learn more about contributing: https://reactjs.org/docs/how-to-contribute.html --> ## 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 <poteto@users.noreply.github.com>

michael faith committed Feb 16, 2025 at 13:10 UTC 5adf40208f4a2f56bda5c059d18ce578c5091dab
14 files changed +574 -857
packages/eslint-plugin-react-hooks/babel.config.js new
+8
@@ -0,0 +1,8 @@
1 +/**
2 + * This file is purely being used for local jest runs, and doesn't participate in the build process.
3 + */
4 +'use strict';
5 +
6 +module.exports = {
7 + extends: '../../babel.config-ts.js',
8 +};
packages/eslint-plugin-react-hooks/index.js
+1 -8
@@ -1,8 +1 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -export * from './src/index';
1 +module.exports = require('./src/index.ts');
packages/eslint-plugin-react-hooks/jest.config.js new
+8
@@ -0,0 +1,8 @@
1 +'use strict';
2 +
3 +process.env.NODE_ENV = 'development';
4 +
5 +module.exports = {
6 + setupFiles: [require.resolve('../../scripts/jest/setupEnvironment.js')],
7 + moduleFileExtensions: ['ts', 'js', 'json'],
8 +};
packages/eslint-plugin-react-hooks/npm/index.d.ts new
+1
@@ -0,0 +1 @@
1 +export * from './cjs/eslint-plugin-react-hooks';
packages/eslint-plugin-react-hooks/package.json
+9 -2
@@ -10,8 +10,9 @@
10 "files": [
11 "LICENSE",
12 "README.md",
13 + "cjs",
14 "index.js",
14 - "cjs"
15 + "index.d.ts"
16 ],
17 "keywords": [
18 "eslint",
@@ -19,10 +20,16 @@
20 "eslintplugin",
21 "react"
22 ],
23 + "scripts": {
24 + "test": "jest",
25 + "typecheck": "tsc --noEmit"
26 + },
27 "license": "MIT",
28 "bugs": {
29 "url": "https://github.com/facebook/react/issues"
30 },
31 + "main": "./index.js",
32 + "types": "./index.d.ts",
33 "engines": {
34 "node": ">=10"
35 },
@@ -32,6 +39,7 @@
39 },
40 "devDependencies": {
41 "@babel/eslint-parser": "^7.11.4",
42 + "@babel/preset-typescript": "^7.26.0",
43 "@tsconfig/strictest": "^2.0.5",
44 "@typescript-eslint/parser-v2": "npm:@typescript-eslint/parser@^2.26.0",
45 "@typescript-eslint/parser-v3": "npm:@typescript-eslint/parser@^3.10.0",
@@ -45,7 +53,6 @@
53 "eslint-v7": "npm:eslint@^7.7.0",
54 "eslint-v9": "npm:eslint@^9.0.0",
55 "jest": "^29.5.0",
48 - "tsup": "^8.3.5",
56 "typescript": "^5.4.3"
57 }
58 }
packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.ts renamed
+388 -243
@@ -4,12 +4,41 @@
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7 -
7 /* eslint-disable no-for-of-loops/no-for-of-loops */
8 +import type {Rule, Scope} from 'eslint';
9 +import type {
10 + ArrayExpression,
11 + ArrowFunctionExpression,
12 + CallExpression,
13 + Expression,
14 + FunctionDeclaration,
15 + FunctionExpression,
16 + Identifier,
17 + Node,
18 + Pattern,
19 + PrivateIdentifier,
20 + Super,
21 + VariableDeclarator,
22 +} from 'estree';
23 +
24 +type DeclaredDependency = {
25 + key: string;
26 + node: Node;
27 +};
28
10 -'use strict';
29 +type Dependency = {
30 + isStable: boolean;
31 + references: Scope.Reference[];
32 +};
33 +
34 +type DependencyTreeNode = {
35 + isUsed: boolean; // True if used in code
36 + isSatisfiedRecursively: boolean; // True if specified in deps
37 + isSubtreeUsed: boolean; // True if something deeper is used by code
38 + children: Map<string, DependencyTreeNode>; // Nodes for properties
39 +};
40
12 -export default {
41 +const rule = {
42 meta: {
43 type: 'suggestion',
44 docs: {
@@ -36,7 +65,7 @@ export default {
65 },
66 ],
67 },
39 - create(context) {
68 + create(context: Rule.RuleContext) {
69 // Parse the `additionalHooks` regex.
70 const additionalHooks =
71 context.options &&
@@ -45,7 +74,7 @@ export default {
74 ? new RegExp(context.options[0].additionalHooks)
75 : undefined;
76
48 - const enableDangerousAutofixThisMayCauseInfiniteLoops =
77 + const enableDangerousAutofixThisMayCauseInfiniteLoops: boolean =
78 (context.options &&
79 context.options[0] &&
80 context.options[0].enableDangerousAutofixThisMayCauseInfiniteLoops) ||
@@ -56,11 +85,15 @@ export default {
85 enableDangerousAutofixThisMayCauseInfiniteLoops,
86 };
87
59 - function reportProblem(problem) {
88 + function reportProblem(problem: Rule.ReportDescriptor) {
89 if (enableDangerousAutofixThisMayCauseInfiniteLoops) {
90 // Used to enable legacy behavior. Dangerous.
91 // Keep this as an option until major IDEs upgrade (including VSCode FB ESLint extension).
63 - if (Array.isArray(problem.suggest) && problem.suggest.length > 0) {
92 + if (
93 + Array.isArray(problem.suggest) &&
94 + problem.suggest.length > 0 &&
95 + problem.suggest[0]
96 + ) {
97 problem.fix = problem.suggest[0].fix;
98 }
99 }
@@ -68,15 +101,15 @@ export default {
101 }
102
103 /**
71 - * SourceCode#getText that also works down to ESLint 3.0.0
104 + * SourceCode that also works down to ESLint 3.0.0
105 */
73 - const getSource =
74 - typeof context.getSource === 'function'
75 - ? node => {
76 - return context.getSource(node);
106 + const getSourceCode =
107 + typeof context.getSourceCode === 'function'
108 + ? () => {
109 + return context.getSourceCode();
110 }
78 - : node => {
79 - return context.sourceCode.getText(node);
111 + : () => {
112 + return context.sourceCode;
113 };
114 /**
115 * SourceCode#getScope that also works down to ESLint 3.0.0
@@ -86,24 +119,34 @@ export default {
119 ? () => {
120 return context.getScope();
121 }
89 - : node => {
122 + : (node: Node) => {
123 return context.sourceCode.getScope(node);
124 };
125
93 - const scopeManager = context.getSourceCode().scopeManager;
126 + const scopeManager = getSourceCode().scopeManager;
127
128 // Should be shared between visitors.
96 - const setStateCallSites = new WeakMap();
97 - const stateVariables = new WeakSet();
98 - const stableKnownValueCache = new WeakMap();
99 - const functionWithoutCapturedValueCache = new WeakMap();
100 - const useEffectEventVariables = new WeakSet();
101 - function memoizeWithWeakMap(fn, map) {
102 - return function (arg) {
129 + const setStateCallSites = new WeakMap<
130 + Expression | Super,
131 + Pattern | null | undefined
132 + >();
133 + const stateVariables = new WeakSet<Identifier>();
134 + const stableKnownValueCache = new WeakMap<Scope.Variable, boolean>();
135 + const functionWithoutCapturedValueCache = new WeakMap<
136 + Scope.Variable,
137 + boolean
138 + >();
139 + const useEffectEventVariables = new WeakSet<Expression>();
140 +
141 + function memoizeWithWeakMap(
142 + fn: (resolved: Scope.Variable) => boolean,
143 + map: WeakMap<Scope.Variable, boolean>,
144 + ) {
145 + return function (arg: Scope.Variable): boolean {
146 if (map.has(arg)) {
147 // to verify cache hits:
148 // console.log(arg.name)
106 - return map.get(arg);
149 + return map.get(arg)!;
150 }
151 const result = fn(arg);
152 map.set(arg, result);
@@ -114,12 +157,12 @@ export default {
157 * Visitor for both function expressions and arrow function expressions.
158 */
159 function visitFunctionWithDependencies(
117 - node,
118 - declaredDependenciesNode,
119 - reactiveHook,
120 - reactiveHookName,
121 - isEffect,
122 - ) {
160 + node: ArrowFunctionExpression | FunctionDeclaration | FunctionExpression,
161 + declaredDependenciesNode: Node | undefined,
162 + reactiveHook: Node,
163 + reactiveHookName: string,
164 + isEffect: boolean,
165 + ): void {
166 if (isEffect && node.async) {
167 reportProblem({
168 node: node,
@@ -140,6 +183,9 @@ export default {
183
184 // Get the current scope.
185 const scope = scopeManager.acquire(node);
186 + if (!scope) {
187 + return;
188 + }
189
190 // Find all our "pure scopes". On every re-render of a component these
191 // pure scopes may have changes to the variables declared within. So all
@@ -150,7 +196,7 @@ export default {
196 // scope. We can't enforce this in a lint so we trust that all variables
197 // declared outside of pure scope are indeed frozen.
198 const pureScopes = new Set();
153 - let componentScope = null;
199 + let componentScope: Scope.Scope | null = null;
200 {
201 let currentScope = scope.upper;
202 while (currentScope) {
@@ -186,7 +232,7 @@ export default {
232 // const onStuff = useEffectEvent(() => {})
233 // ^^^ true for this reference
234 // False for everything else.
189 - function isStableKnownHookValue(resolved) {
235 + function isStableKnownHookValue(resolved: Scope.Variable): boolean {
236 if (!isArray(resolved.defs)) {
237 return false;
238 }
@@ -195,10 +241,11 @@ export default {
241 return false;
242 }
243 // Look for `let stuff = ...`
198 - if (def.node.type !== 'VariableDeclarator') {
244 + const defNode: VariableDeclarator = def.node;
245 + if (defNode.type !== 'VariableDeclarator') {
246 return false;
247 }
201 - let init = def.node.init;
248 + let init = defNode.init;
249 if (init == null) {
250 return false;
251 }
@@ -207,8 +254,8 @@ export default {
254 }
255 // Detect primitive constants
256 // const foo = 42
210 - let declaration = def.node.parent;
211 - if (declaration == null) {
257 + let declaration = defNode.parent;
258 + if (declaration == null && componentScope) {
259 // This might happen if variable is declared after the callback.
260 // In that case ESLint won't set up .parent refs.
261 // So we'll set them up manually.
@@ -219,6 +266,8 @@ export default {
266 }
267 }
268 if (
269 + declaration &&
270 + 'kind' in declaration &&
271 declaration.kind === 'const' &&
272 init.type === 'Literal' &&
273 (typeof init.value === 'string' ||
@@ -233,10 +282,11 @@ export default {
282 if (init.type !== 'CallExpression') {
283 return false;
284 }
236 - let callee = init.callee;
285 + let callee: Expression | PrivateIdentifier | Super = init.callee;
286 // Step into `= React.something` initializer.
287 if (
288 callee.type === 'MemberExpression' &&
289 + 'name' in callee.object &&
290 callee.object.name === 'React' &&
291 callee.property != null &&
292 !callee.computed
@@ -246,7 +296,8 @@ export default {
296 if (callee.type !== 'Identifier') {
297 return false;
298 }
249 - const id = def.node.id;
299 + const definitionNode: VariableDeclarator = def.node;
300 + const id = definitionNode.id;
301 const {name} = callee;
302 if (name === 'useRef' && id.type === 'Identifier') {
303 // useRef() return value is stable.
@@ -256,6 +307,7 @@ export default {
307 id.type === 'Identifier'
308 ) {
309 for (const ref of resolved.references) {
310 + // @ts-expect-error These types are not compatible (Reference and Identifier)
311 if (ref !== id) {
312 useEffectEventVariables.add(ref.identifier);
313 }
@@ -278,17 +330,14 @@ export default {
330 if (name === 'useState') {
331 const references = resolved.references;
332 let writeCount = 0;
281 - for (let i = 0; i < references.length; i++) {
282 - if (references[i].isWrite()) {
333 + for (const reference of references) {
334 + if (reference.isWrite()) {
335 writeCount++;
336 }
337 if (writeCount > 1) {
338 return false;
339 }
288 - setStateCallSites.set(
289 - references[i].identifier,
290 - id.elements[0],
291 - );
340 + setStateCallSites.set(reference.identifier, id.elements[0]);
341 }
342 }
343 // Setter is stable.
@@ -296,8 +345,8 @@ export default {
345 } else if (id.elements[0] === resolved.identifiers[0]) {
346 if (name === 'useState') {
347 const references = resolved.references;
299 - for (let i = 0; i < references.length; i++) {
300 - stateVariables.add(references[i].identifier);
348 + for (const reference of references) {
349 + stateVariables.add(reference.identifier);
350 }
351 }
352 // State variable itself is dynamic.
@@ -323,7 +372,9 @@ export default {
372 }
373
374 // Some are just functions that don't reference anything dynamic.
326 - function isFunctionWithoutCapturedValues(resolved) {
375 + function isFunctionWithoutCapturedValues(
376 + resolved: Scope.Variable,
377 + ): boolean {
378 if (!isArray(resolved.defs)) {
379 return false;
380 }
@@ -336,12 +387,10 @@ export default {
387 }
388 // Search the direct component subscopes for
389 // top-level function definitions matching this reference.
339 - const fnNode = def.node;
340 - const childScopes = componentScope.childScopes;
390 + const fnNode: Node = def.node;
391 + const childScopes = componentScope?.childScopes || [];
392 let fnScope = null;
342 - let i;
343 - for (i = 0; i < childScopes.length; i++) {
344 - const childScope = childScopes[i];
393 + for (const childScope of childScopes) {
394 const childScopeBlock = childScope.block;
395 if (
396 // function handleChange() {}
@@ -362,8 +411,7 @@ export default {
411 }
412 // Does this function capture any values
413 // that are in pure scopes (aka render)?
365 - for (i = 0; i < fnScope.through.length; i++) {
366 - const ref = fnScope.through[i];
414 + for (const ref of fnScope.through) {
415 if (ref.resolved == null) {
416 continue;
417 }
@@ -392,15 +440,21 @@ export default {
440 );
441
442 // These are usually mistaken. Collect them.
395 - const currentRefsInEffectCleanup = new Map();
443 + const currentRefsInEffectCleanup = new Map<
444 + string,
445 + {
446 + reference: Scope.Reference;
447 + dependencyNode: Identifier;
448 + }
449 + >();
450
451 // Is this reference inside a cleanup function for this effect node?
452 // We can check by traversing scopes upwards from the reference, and checking
453 // if the last "return () => " we encounter is located directly inside the effect.
400 - function isInsideEffectCleanup(reference) {
401 - let curScope = reference.from;
454 + function isInsideEffectCleanup(reference: Scope.Reference): boolean {
455 + let curScope: Scope.Scope | null = reference.from;
456 let isInReturnedFunction = false;
403 - while (curScope.block !== node) {
457 + while (curScope && curScope.block !== node) {
458 if (curScope.type === 'function') {
459 isInReturnedFunction =
460 curScope.block.parent != null &&
@@ -413,11 +467,11 @@ export default {
467
468 // Get dependencies from all our resolved references in pure scopes.
469 // Key is dependency string, value is whether it's stable.
416 - const dependencies = new Map();
417 - const optionalChains = new Map();
470 + const dependencies = new Map<string, Dependency>();
471 + const optionalChains = new Map<string, boolean>();
472 gatherDependenciesRecursively(scope);
473
420 - function gatherDependenciesRecursively(currentScope) {
474 + function gatherDependenciesRecursively(currentScope: Scope.Scope): void {
475 for (const reference of currentScope.references) {
476 // If this reference is not resolved or it is not declared in a pure
477 // scope then we don't care about this reference.
@@ -434,6 +488,9 @@ export default {
488 node,
489 reference.identifier,
490 );
491 + if (referenceNode == null) {
492 + continue;
493 + }
494 const dependencyNode = getDependency(referenceNode);
495 const dependency = analyzePropertyChain(
496 dependencyNode,
@@ -446,8 +503,8 @@ export default {
503 isEffect &&
504 // ... and this look like accessing .current...
505 dependencyNode.type === 'Identifier' &&
449 - (dependencyNode.parent.type === 'MemberExpression' ||
450 - dependencyNode.parent.type === 'OptionalMemberExpression') &&
506 + (dependencyNode.parent?.type === 'MemberExpression' ||
507 + dependencyNode.parent?.type === 'OptionalMemberExpression') &&
508 !dependencyNode.parent.computed &&
509 dependencyNode.parent.property.type === 'Identifier' &&
510 dependencyNode.parent.property.name === 'current' &&
@@ -461,8 +518,8 @@ export default {
518 }
519
520 if (
464 - dependencyNode.parent.type === 'TSTypeQuery' ||
465 - dependencyNode.parent.type === 'TSTypeReference'
521 + dependencyNode.parent?.type === 'TSTypeQuery' ||
522 + dependencyNode.parent?.type === 'TSTypeReference'
523 ) {
524 continue;
525 }
@@ -472,10 +529,11 @@ export default {
529 continue;
530 }
531 // Ignore references to the function itself as it's not defined yet.
475 - if (def.node != null && def.node.init === node.parent) {
532 + if (def.node && def.node.init === node.parent) {
533 continue;
534 }
535 // Ignore Flow type parameters
536 + // @ts-expect-error We don't have flow types
537 if (def.type === 'TypeParameter') {
538 continue;
539 }
@@ -492,7 +550,7 @@ export default {
550 references: [reference],
551 });
552 } else {
495 - dependencies.get(dependency).references.push(reference);
553 + dependencies.get(dependency)?.references.push(reference);
554 }
555 }
556
@@ -504,12 +562,12 @@ export default {
562 // Warn about accessing .current in cleanup effects.
563 currentRefsInEffectCleanup.forEach(
564 ({reference, dependencyNode}, dependency) => {
507 - const references = reference.resolved.references;
565 + const references = reference.resolved?.references || [];
566 // Is React managing this ref or us?
567 // Let's see if we can find a .current assignment.
568 let foundCurrentAssignment = false;
511 - for (let i = 0; i < references.length; i++) {
512 - const {identifier} = references[i];
569 + for (const reference of references) {
570 + const {identifier} = reference;
571 const {parent} = identifier;
572 if (
573 parent != null &&
@@ -520,7 +578,7 @@ export default {
578 parent.property.type === 'Identifier' &&
579 parent.property.name === 'current' &&
580 // ref.current = <something>
523 - parent.parent.type === 'AssignmentExpression' &&
581 + parent.parent?.type === 'AssignmentExpression' &&
582 parent.parent.left === parent
583 ) {
584 foundCurrentAssignment = true;
@@ -532,6 +590,7 @@ export default {
590 return;
591 }
592 reportProblem({
593 + // @ts-expect-error We can do better here (dependencyNode.parent has not been type narrowed)
594 node: dependencyNode.parent.property,
595 message:
596 `The ref value '${dependency}.current' will likely have ` +
@@ -545,8 +604,8 @@ export default {
604
605 // Warn about assigning to variables in the outer scope.
606 // Those are usually bugs.
548 - const staleAssignments = new Set();
549 - function reportStaleAssignment(writeExpr, key) {
607 + const staleAssignments = new Set<string>();
608 + function reportStaleAssignment(writeExpr: Node, key: string): void {
609 if (staleAssignments.has(key)) {
610 return;
611 }
@@ -555,16 +614,16 @@ export default {
614 node: writeExpr,
615 message:
616 `Assignments to the '${key}' variable from inside React Hook ` +
558 - `${getSource(reactiveHook)} will be lost after each ` +
617 + `${getSourceCode().getText(reactiveHook)} will be lost after each ` +
618 `render. To preserve the value over time, store it in a useRef ` +
619 `Hook and keep the mutable value in the '.current' property. ` +
620 `Otherwise, you can move this variable directly inside ` +
562 - `${getSource(reactiveHook)}.`,
621 + `${getSourceCode().getText(reactiveHook)}.`,
622 });
623 }
624
625 // Remember which deps are stable and report bad usage first.
567 - const stableDependencies = new Set();
626 + const stableDependencies = new Set<string>();
627 dependencies.forEach(({isStable, references}, key) => {
628 if (isStable) {
629 stableDependencies.add(key);
@@ -584,8 +643,8 @@ export default {
643 if (!declaredDependenciesNode) {
644 // Check if there are any top-level setState() calls.
645 // Those tend to lead to infinite loops.
587 - let setStateInsideEffectWithoutDeps = null;
588 - dependencies.forEach(({isStable, references}, key) => {
646 + let setStateInsideEffectWithoutDeps: string | null = null;
647 + dependencies.forEach(({references}, key) => {
648 if (setStateInsideEffectWithoutDeps) {
649 return;
650 }
@@ -600,11 +659,11 @@ export default {
659 return;
660 }
661
603 - let fnScope = reference.from;
604 - while (fnScope.type !== 'function') {
662 + let fnScope: Scope.Scope | null = reference.from;
663 + while (fnScope && fnScope.type !== 'function') {
664 fnScope = fnScope.upper;
665 }
607 - const isDirectlyInsideEffect = fnScope.block === node;
666 + const isDirectlyInsideEffect = fnScope?.block === node;
667 if (isDirectlyInsideEffect) {
668 // TODO: we could potentially ignore early returns.
669 setStateInsideEffectWithoutDeps = key;
@@ -616,7 +675,7 @@ export default {
675 dependencies,
676 declaredDependencies: [],
677 stableDependencies,
619 - externalDependencies: new Set(),
678 + externalDependencies: new Set<string>(),
679 isEffect: true,
680 });
681 reportProblem({
@@ -645,8 +704,8 @@ export default {
704 return;
705 }
706
648 - const declaredDependencies = [];
649 - const externalDependencies = new Set();
707 + const declaredDependencies: DeclaredDependency[] = [];
708 + const externalDependencies = new Set<string>();
709 const isArrayExpression =
710 declaredDependenciesNode.type === 'ArrayExpression';
711 const isTSAsArrayExpression =
@@ -660,7 +719,7 @@ export default {
719 reportProblem({
720 node: declaredDependenciesNode,
721 message:
663 - `React Hook ${getSource(reactiveHook)} was passed a ` +
722 + `React Hook ${getSourceCode().getText(reactiveHook)} was passed a ` +
723 'dependency list that is not an array literal. This means we ' +
724 "can't statically verify whether you've passed the correct " +
725 'dependencies.',
@@ -670,108 +729,117 @@ export default {
729 ? declaredDependenciesNode.expression
730 : declaredDependenciesNode;
731
673 - arrayExpression.elements.forEach(declaredDependencyNode => {
674 - // Skip elided elements.
675 - if (declaredDependencyNode === null) {
676 - return;
677 - }
678 - // If we see a spread element then add a special warning.
679 - if (declaredDependencyNode.type === 'SpreadElement') {
680 - reportProblem({
681 - node: declaredDependencyNode,
682 - message:
683 - `React Hook ${getSource(reactiveHook)} has a spread ` +
684 - "element in its dependency array. This means we can't " +
685 - "statically verify whether you've passed the " +
686 - 'correct dependencies.',
687 - });
688 - return;
689 - }
690 - if (useEffectEventVariables.has(declaredDependencyNode)) {
691 - reportProblem({
692 - node: declaredDependencyNode,
693 - message:
694 - 'Functions returned from `useEffectEvent` must not be included in the dependency array. ' +
695 - `Remove \`${getSource(
696 - declaredDependencyNode,
697 - )}\` from the list.`,
698 - suggest: [
699 - {
700 - desc: `Remove the dependency \`${getSource(
732 + (arrayExpression as ArrayExpression).elements.forEach(
733 + declaredDependencyNode => {
734 + // Skip elided elements.
735 + if (declaredDependencyNode === null) {
736 + return;
737 + }
738 + // If we see a spread element then add a special warning.
739 + if (declaredDependencyNode.type === 'SpreadElement') {
740 + reportProblem({
741 + node: declaredDependencyNode,
742 + message:
743 + `React Hook ${getSourceCode().getText(reactiveHook)} has a spread ` +
744 + "element in its dependency array. This means we can't " +
745 + "statically verify whether you've passed the " +
746 + 'correct dependencies.',
747 + });
748 + return;
749 + }
750 + if (useEffectEventVariables.has(declaredDependencyNode)) {
751 + reportProblem({
752 + node: declaredDependencyNode,
753 + message:
754 + 'Functions returned from `useEffectEvent` must not be included in the dependency array. ' +
755 + `Remove \`${getSourceCode().getText(
756 declaredDependencyNode,
702 - )}\``,
703 - fix(fixer) {
704 - return fixer.removeRange(declaredDependencyNode.range);
757 + )}\` from the list.`,
758 + suggest: [
759 + {
760 + desc: `Remove the dependency \`${getSourceCode().getText(
761 + declaredDependencyNode,
762 + )}\``,
763 + fix(fixer) {
764 + return fixer.removeRange(declaredDependencyNode.range!);
765 + },
766 },
706 - },
707 - ],
708 - });
709 - }
710 - // Try to normalize the declared dependency. If we can't then an error
711 - // will be thrown. We will catch that error and report an error.
712 - let declaredDependency;
713 - try {
714 - declaredDependency = analyzePropertyChain(
715 - declaredDependencyNode,
716 - null,
717 - );
718 - } catch (error) {
719 - if (/Unsupported node type/.test(error.message)) {
720 - if (declaredDependencyNode.type === 'Literal') {
721 - if (dependencies.has(declaredDependencyNode.value)) {
722 - reportProblem({
723 - node: declaredDependencyNode,
724 - message:
725 - `The ${declaredDependencyNode.raw} literal is not a valid dependency ` +
726 - `because it never changes. ` +
727 - `Did you mean to include ${declaredDependencyNode.value} in the array instead?`,
728 - });
767 + ],
768 + });
769 + }
770 + // Try to normalize the declared dependency. If we can't then an error
771 + // will be thrown. We will catch that error and report an error.
772 + let declaredDependency;
773 + try {
774 + declaredDependency = analyzePropertyChain(
775 + declaredDependencyNode,
776 + null,
777 + );
778 + } catch (error: unknown) {
779 + if (
780 + error instanceof Error &&
781 + /Unsupported node type/.test(error.message)
782 + ) {
783 + if (declaredDependencyNode.type === 'Literal') {
784 + if (
785 + declaredDependencyNode.value &&
786 + dependencies.has(declaredDependencyNode.value as string)
787 + ) {
788 + reportProblem({
789 + node: declaredDependencyNode,
790 + message:
791 + `The ${declaredDependencyNode.raw} literal is not a valid dependency ` +
792 + `because it never changes. ` +
793 + `Did you mean to include ${declaredDependencyNode.value} in the array instead?`,
794 + });
795 + } else {
796 + reportProblem({
797 + node: declaredDependencyNode,
798 + message:
799 + `The ${declaredDependencyNode.raw} literal is not a valid dependency ` +
800 + 'because it never changes. You can safely remove it.',
801 + });
802 + }
803 } else {
804 reportProblem({
805 node: declaredDependencyNode,
806 message:
733 - `The ${declaredDependencyNode.raw} literal is not a valid dependency ` +
734 - 'because it never changes. You can safely remove it.',
807 + `React Hook ${getSourceCode().getText(reactiveHook)} has a ` +
808 + `complex expression in the dependency array. ` +
809 + 'Extract it to a separate variable so it can be statically checked.',
810 });
811 }
812 +
813 + return;
814 } else {
738 - reportProblem({
739 - node: declaredDependencyNode,
740 - message:
741 - `React Hook ${getSource(reactiveHook)} has a ` +
742 - `complex expression in the dependency array. ` +
743 - 'Extract it to a separate variable so it can be statically checked.',
744 - });
815 + throw error;
816 }
746 -
747 - return;
748 - } else {
749 - throw error;
817 }
751 - }
818
753 - let maybeID = declaredDependencyNode;
754 - while (
755 - maybeID.type === 'MemberExpression' ||
756 - maybeID.type === 'OptionalMemberExpression' ||
757 - maybeID.type === 'ChainExpression'
758 - ) {
759 - maybeID = maybeID.object || maybeID.expression.object;
760 - }
761 - const isDeclaredInComponent = !componentScope.through.some(
762 - ref => ref.identifier === maybeID,
763 - );
819 + let maybeID = declaredDependencyNode;
820 + while (
821 + maybeID.type === 'MemberExpression' ||
822 + maybeID.type === 'OptionalMemberExpression' ||
823 + maybeID.type === 'ChainExpression'
824 + ) {
825 + // @ts-expect-error This can be done better
826 + maybeID = maybeID.object || maybeID.expression.object;
827 + }
828 + const isDeclaredInComponent = !componentScope.through.some(
829 + ref => ref.identifier === maybeID,
830 + );
831
765 - // Add the dependency to our declared dependency map.
766 - declaredDependencies.push({
767 - key: declaredDependency,
768 - node: declaredDependencyNode,
769 - });
832 + // Add the dependency to our declared dependency map.
833 + declaredDependencies.push({
834 + key: declaredDependency,
835 + node: declaredDependencyNode,
836 + });
837
771 - if (!isDeclaredInComponent) {
772 - externalDependencies.add(declaredDependency);
773 - }
774 - });
838 + if (!isDeclaredInComponent) {
839 + externalDependencies.add(declaredDependency);
840 + }
841 + },
842 + );
843 }
844
845 const {
@@ -824,10 +892,10 @@ export default {
892
893 const message =
894 `The '${construction.name.name}' ${depType} ${causation} the dependencies of ` +
827 - `${reactiveHookName} Hook (at line ${declaredDependenciesNode.loc.start.line}) ` +
895 + `${reactiveHookName} Hook (at line ${declaredDependenciesNode.loc?.start.line}) ` +
896 `change on every render. ${advice}`;
897
830 - let suggest;
898 + let suggest: Rule.ReportDescriptor['suggest'];
899 // Only handle the simple case of variable assignments.
900 // Wrapping function declarations can mess up hoisting.
901 if (
@@ -848,12 +916,12 @@ export default {
916 : ['useCallback(', ')'];
917 return [
918 // TODO: also add an import?
851 - fixer.insertTextBefore(construction.node.init, before),
919 + fixer.insertTextBefore(construction.node.init!, before),
920 // TODO: ideally we'd gather deps here but it would require
921 // restructuring the rule code. This will cause a new lint
922 // error to appear immediately for useCallback. Note we're
923 // not adding [] because would that changes semantics.
856 - fixer.insertTextAfter(construction.node.init, after),
924 + fixer.insertTextAfter(construction.node.init!, after),
925 ];
926 },
927 },
@@ -889,7 +957,7 @@ export default {
957 }
958
959 // Alphabetize the suggestions, but only if deps were already alphabetized.
892 - function areDeclaredDepsAlphabetized() {
960 + function areDeclaredDepsAlphabetized(): boolean {
961 if (declaredDependencies.length === 0) {
962 return true;
963 }
@@ -905,7 +973,7 @@ export default {
973 // This function is the last step before printing a dependency, so now is a good time to
974 // check whether any members in our path are always used as optional-only. In that case,
975 // we will use ?. instead of . to concatenate those parts of the path.
908 - function formatDependency(path) {
976 + function formatDependency(path: string): string {
977 const members = path.split('.');
978 let finalPath = '';
979 for (let i = 0; i < members.length; i++) {
@@ -919,7 +987,12 @@ export default {
987 return finalPath;
988 }
989
922 - function getWarningMessage(deps, singlePrefix, label, fixVerb) {
990 + function getWarningMessage(
991 + deps: Set<string>,
992 + singlePrefix: string,
993 + label: string,
994 + fixVerb: string,
995 + ): string | null {
996 if (deps.size === 0) {
997 return null;
998 }
@@ -942,7 +1015,7 @@ export default {
1015
1016 let extraWarning = '';
1017 if (unnecessaryDependencies.size > 0) {
945 - let badRef = null;
1018 + let badRef: string | null = null;
1019 Array.from(unnecessaryDependencies.keys()).forEach(key => {
1020 if (badRef !== null) {
1021 return;
@@ -956,7 +1029,7 @@ export default {
1029 ` Mutable values like '${badRef}' aren't valid dependencies ` +
1030 "because mutating them doesn't re-render the component.";
1031 } else if (externalDependencies.size > 0) {
959 - const dep = Array.from(externalDependencies)[0];
1032 + const dep = Array.from(externalDependencies)[0]!;
1033 // Don't show this warning for things that likely just got moved *inside* the callback
1034 // because in that case they're clearly not referring to globals.
1035 if (!scope.set.has(dep)) {
@@ -980,8 +1053,7 @@ export default {
1053 return;
1054 }
1055 let isPropsOnlyUsedInMembers = true;
983 - for (let i = 0; i < refs.length; i++) {
984 - const ref = refs[i];
1056 + for (const ref of refs) {
1057 const id = fastFindReferenceWithParent(
1058 componentScope.block,
1059 ref.identifier,
@@ -1008,14 +1080,14 @@ export default {
1080 ` However, 'props' will change when *any* prop changes, so the ` +
1081 `preferred fix is to destructure the 'props' object outside of ` +
1082 `the ${reactiveHookName} call and refer to those specific props ` +
1011 - `inside ${getSource(reactiveHook)}.`;
1083 + `inside ${getSourceCode().getText(reactiveHook)}.`;
1084 }
1085 }
1086
1087 if (!extraWarning && missingDependencies.size > 0) {
1088 // See if the user is trying to avoid specifying a callable prop.
1089 // This usually means they're unaware of useCallback.
1018 - let missingCallbackDep = null;
1090 + let missingCallbackDep: string | null = null;
1091 missingDependencies.forEach(missingDep => {
1092 if (missingCallbackDep) {
1093 return;
@@ -1023,19 +1095,22 @@ export default {
1095 // Is this a variable from top scope?
1096 const topScopeRef = componentScope.set.get(missingDep);
1097 const usedDep = dependencies.get(missingDep);
1026 - if (usedDep.references[0].resolved !== topScopeRef) {
1098 + if (
1099 + !usedDep?.references ||
1100 + usedDep?.references[0]?.resolved !== topScopeRef
1101 + ) {
1102 return;
1103 }
1104 // Is this a destructured prop?
1030 - const def = topScopeRef.defs[0];
1105 + const def = topScopeRef?.defs[0];
1106 if (def == null || def.name == null || def.type !== 'Parameter') {
1107 return;
1108 }
1109 // Was it called in at least one case? Then it's a function.
1110 let isFunctionCall = false;
1036 - let id;
1037 - for (let i = 0; i < usedDep.references.length; i++) {
1038 - id = usedDep.references[i].identifier;
1111 + let id: Identifier | undefined;
1112 + for (const reference of usedDep.references) {
1113 + id = reference.identifier;
1114 if (
1115 id != null &&
1116 id.parent != null &&
@@ -1064,17 +1139,21 @@ export default {
1139 }
1140
1141 if (!extraWarning && missingDependencies.size > 0) {
1067 - let setStateRecommendation = null;
1068 - missingDependencies.forEach(missingDep => {
1142 + let setStateRecommendation: {
1143 + missingDep: string;
1144 + setter: string;
1145 + form: 'reducer' | 'updater' | 'inlineReducer';
1146 + } | null = null;
1147 + for (const missingDep of missingDependencies) {
1148 if (setStateRecommendation !== null) {
1070 - return;
1149 + break;
1150 }
1072 - const usedDep = dependencies.get(missingDep);
1151 + const usedDep = dependencies.get(missingDep)!;
1152 const references = usedDep.references;
1153 let id;
1154 let maybeCall;
1076 - for (let i = 0; i < references.length; i++) {
1077 - id = references[i].identifier;
1155 + for (const reference of references) {
1156 + id = reference.identifier;
1157 maybeCall = id.parent;
1158 // Try to see if we have setState(someExpr(missingDep)).
1159 while (maybeCall != null && maybeCall !== componentScope.block) {
@@ -1083,22 +1162,27 @@ export default {
1162 maybeCall.callee,
1163 );
1164 if (correspondingStateVariable != null) {
1086 - if (correspondingStateVariable.name === missingDep) {
1165 + if (
1166 + 'name' in correspondingStateVariable &&
1167 + correspondingStateVariable.name === missingDep
1168 + ) {
1169 // setCount(count + 1)
1170 setStateRecommendation = {
1171 missingDep,
1090 - setter: maybeCall.callee.name,
1172 + setter:
1173 + 'name' in maybeCall.callee ? maybeCall.callee.name : '',
1174 form: 'updater',
1175 };
1176 } else if (stateVariables.has(id)) {
1177 // setCount(count + increment)
1178 setStateRecommendation = {
1179 missingDep,
1097 - setter: maybeCall.callee.name,
1180 + setter:
1181 + 'name' in maybeCall.callee ? maybeCall.callee.name : '',
1182 form: 'reducer',
1183 };
1184 } else {
1101 - const resolved = references[i].resolved;
1185 + const resolved = reference.resolved;
1186 if (resolved != null) {
1187 // If it's a parameter *and* a missing dep,
1188 // it must be a prop or something inside a prop.
@@ -1107,7 +1191,10 @@ export default {
1191 if (def != null && def.type === 'Parameter') {
1192 setStateRecommendation = {
1193 missingDep,
1110 - setter: maybeCall.callee.name,
1194 + setter:
1195 + 'name' in maybeCall.callee
1196 + ? maybeCall.callee.name
1197 + : '',
1198 form: 'inlineReducer',
1199 };
1200 }
@@ -1122,7 +1209,7 @@ export default {
1209 break;
1210 }
1211 }
1125 - });
1212 + }
1213 if (setStateRecommendation !== null) {
1214 switch (setStateRecommendation.form) {
1215 case 'reducer':
@@ -1158,7 +1245,7 @@ export default {
1245 reportProblem({
1246 node: declaredDependenciesNode,
1247 message:
1161 - `React Hook ${getSource(reactiveHook)} has ` +
1248 + `React Hook ${getSourceCode().getText(reactiveHook)} has ` +
1249 // To avoid a long message, show the next actionable item.
1250 (getWarningMessage(missingDependencies, 'a', 'missing', 'include') ||
1251 getWarningMessage(
@@ -1191,7 +1278,7 @@ export default {
1278 });
1279 }
1280
1194 - function visitCallExpression(node) {
1281 + function visitCallExpression(node: CallExpression): void {
1282 const callbackIndex = getReactiveHookCallbackIndex(node.callee, options);
1283 if (callbackIndex === -1) {
1284 // Not a React Hook call that needs deps.
@@ -1199,7 +1286,9 @@ export default {
1286 }
1287 let callback = node.arguments[callbackIndex];
1288 const reactiveHook = node.callee;
1202 - const reactiveHookName = getNodeWithoutReactNamespace(reactiveHook).name;
1289 + const nodeWithoutNamespace = getNodeWithoutReactNamespace(reactiveHook);
1290 + const reactiveHookName =
1291 + 'name' in nodeWithoutNamespace ? nodeWithoutNamespace.name : '';
1292 const maybeNode = node.arguments[callbackIndex + 1];
1293 const declaredDependenciesNode =
1294 maybeNode &&
@@ -1268,6 +1357,7 @@ export default {
1357 // The function passed as a callback is not written inline.
1358 // But perhaps it's in the dependencies array?
1359 if (
1360 + 'elements' in declaredDependenciesNode &&
1361 declaredDependenciesNode.elements &&
1362 declaredDependenciesNode.elements.some(
1363 el => el && el.type === 'Identifier' && el.name === callback.name,
@@ -1368,7 +1458,7 @@ export default {
1458 CallExpression: visitCallExpression,
1459 };
1460 },
1371 -};
1461 +} satisfies Rule.RuleModule;
1462
1463 // The meat of the logic.
1464 function collectRecommendations({
@@ -1377,6 +1467,12 @@ function collectRecommendations({
1467 stableDependencies,
1468 externalDependencies,
1469 isEffect,
1470 +}: {
1471 + dependencies: Map<string, Dependency>;
1472 + declaredDependencies: DeclaredDependency[];
1473 + stableDependencies: Set<string>;
1474 + externalDependencies: Set<string>;
1475 + isEffect: boolean;
1476 }) {
1477 // Our primary data structure.
1478 // It is a logical representation of property chains:
@@ -1388,7 +1484,7 @@ function collectRecommendations({
1484 // and the nodes that were *declared* as deps. Then we will
1485 // traverse it to learn which deps are missing or unnecessary.
1486 const depTree = createDepTree();
1391 - function createDepTree() {
1487 + function createDepTree(): DependencyTreeNode {
1488 return {
1489 isUsed: false, // True if used in code
1490 isSatisfiedRecursively: false, // True if specified in deps
@@ -1419,7 +1515,10 @@ function collectRecommendations({
1515 });
1516
1517 // Tree manipulation helpers.
1422 - function getOrCreateNodeByPath(rootNode, path) {
1518 + function getOrCreateNodeByPath(
1519 + rootNode: DependencyTreeNode,
1520 + path: string,
1521 + ): DependencyTreeNode {
1522 const keys = path.split('.');
1523 let node = rootNode;
1524 for (const key of keys) {
@@ -1432,7 +1531,11 @@ function collectRecommendations({
1531 }
1532 return node;
1533 }
1435 - function markAllParentsByPath(rootNode, path, fn) {
1534 + function markAllParentsByPath(
1535 + rootNode: DependencyTreeNode,
1536 + path: string,
1537 + fn: (node: DependencyTreeNode) => void,
1538 + ): void {
1539 const keys = path.split('.');
1540 let node = rootNode;
1541 for (const key of keys) {
@@ -1446,15 +1549,20 @@ function collectRecommendations({
1549 }
1550
1551 // Now we can learn which dependencies are missing or necessary.
1449 - const missingDependencies = new Set();
1450 - const satisfyingDependencies = new Set();
1552 + const missingDependencies = new Set<string>();
1553 + const satisfyingDependencies = new Set<string>();
1554 scanTreeRecursively(
1555 depTree,
1556 missingDependencies,
1557 satisfyingDependencies,
1558 key => key,
1559 );
1457 - function scanTreeRecursively(node, missingPaths, satisfyingPaths, keyToPath) {
1560 + function scanTreeRecursively(
1561 + node: DependencyTreeNode,
1562 + missingPaths: Set<string>,
1563 + satisfyingPaths: Set<string>,
1564 + keyToPath: (key: string) => string,
1565 + ): void {
1566 node.children.forEach((child, key) => {
1567 const path = keyToPath(key);
1568 if (child.isSatisfiedRecursively) {
@@ -1484,9 +1592,9 @@ function collectRecommendations({
1592 }
1593
1594 // Collect suggestions in the order they were originally specified.
1487 - const suggestedDependencies = [];
1488 - const unnecessaryDependencies = new Set();
1489 - const duplicateDependencies = new Set();
1595 + const suggestedDependencies: string[] = [];
1596 + const unnecessaryDependencies = new Set<string>();
1597 + const duplicateDependencies = new Set<string>();
1598 declaredDependencies.forEach(({key}) => {
1599 // Does this declared dep satisfy a real need?
1600 if (satisfyingDependencies.has(key)) {
@@ -1532,7 +1640,7 @@ function collectRecommendations({
1640
1641 // If the node will result in constructing a referentially unique value, return
1642 // its human readable type name, else return null.
1535 -function getConstructionExpressionType(node) {
1643 +function getConstructionExpressionType(node: Node): string | null {
1644 switch (node.type) {
1645 case 'ObjectExpression':
1646 return 'object';
@@ -1590,6 +1698,11 @@ function scanForConstructions({
1698 declaredDependenciesNode,
1699 componentScope,
1700 scope,
1701 +}: {
1702 + declaredDependencies: DeclaredDependency[];
1703 + declaredDependenciesNode: Node;
1704 + componentScope: Scope.Scope;
1705 + scope: Scope.Scope;
1706 }) {
1707 const constructions = declaredDependencies
1708 .map(({key}) => {
@@ -1616,7 +1729,7 @@ function scanForConstructions({
1729 const constantExpressionType = getConstructionExpressionType(
1730 node.node.init,
1731 );
1619 - if (constantExpressionType != null) {
1732 + if (constantExpressionType) {
1733 return [ref, constantExpressionType];
1734 }
1735 }
@@ -1634,12 +1747,11 @@ function scanForConstructions({
1747 }
1748 return null;
1749 })
1637 - .filter(Boolean);
1750 + .filter(Boolean) as [Scope.Variable, string][];
1751
1639 - function isUsedOutsideOfHook(ref) {
1752 + function isUsedOutsideOfHook(ref: Scope.Variable): boolean {
1753 let foundWriteExpr = false;
1641 - for (let i = 0; i < ref.references.length; i++) {
1642 - const reference = ref.references[i];
1754 + for (const reference of ref.references) {
1755 if (reference.writeExpr) {
1756 if (foundWriteExpr) {
1757 // Two writes to the same function.
@@ -1650,7 +1762,7 @@ function scanForConstructions({
1762 continue;
1763 }
1764 }
1653 - let currentScope = reference.from;
1765 + let currentScope: Scope.Scope | null = reference.from;
1766 while (currentScope !== scope && currentScope != null) {
1767 currentScope = currentScope.upper;
1768 }
@@ -1666,7 +1778,7 @@ function scanForConstructions({
1778 }
1779
1780 return constructions.map(([ref, depType]) => ({
1669 - construction: ref.defs[0],
1781 + construction: ref.defs[0] as Scope.Definition,
1782 depType,
1783 isUsedOutsideOfHook: isUsedOutsideOfHook(ref),
1784 }));
@@ -1679,11 +1791,13 @@ function scanForConstructions({
1791 * props.foo.(bar) => (props).foo.bar
1792 * props.foo.bar.(baz) => (props).foo.bar.baz
1793 */
1682 -function getDependency(node) {
1794 +function getDependency(node: Node): Node {
1795 if (
1796 + node.parent &&
1797 (node.parent.type === 'MemberExpression' ||
1798 node.parent.type === 'OptionalMemberExpression') &&
1799 node.parent.object === node &&
1800 + 'name' in node.parent.property &&
1801 node.parent.property.name !== 'current' &&
1802 !node.parent.computed &&
1803 !(
@@ -1713,9 +1827,13 @@ function getDependency(node) {
1827 * It just means there is an optional member somewhere inside.
1828 * This particular node might still represent a required member, so check .optional field.
1829 */
1716 -function markNode(node, optionalChains, result) {
1830 +function markNode(
1831 + node: Node,
1832 + optionalChains: Map<string, boolean> | null,
1833 + result: string,
1834 +): void {
1835 if (optionalChains) {
1718 - if (node.optional) {
1836 + if ('optional' in node && node.optional) {
1837 // We only want to consider it optional if *all* usages were optional.
1838 if (!optionalChains.has(result)) {
1839 // Mark as (maybe) optional. If there's a required usage, this will be overridden.
@@ -1735,7 +1853,10 @@ function markNode(node, optionalChains, result) {
1853 * foo.bar(.)baz -> 'foo.bar.baz'
1854 * Otherwise throw.
1855 */
1738 -function analyzePropertyChain(node, optionalChains) {
1856 +function analyzePropertyChain(
1857 + node: Node,
1858 + optionalChains: Map<string, boolean> | null,
1859 +): string {
1860 if (node.type === 'Identifier' || node.type === 'JSXIdentifier') {
1861 const result = node.name;
1862 if (optionalChains) {
@@ -1755,7 +1876,10 @@ function analyzePropertyChain(node, optionalChains) {
1876 const result = `${object}.${property}`;
1877 markNode(node, optionalChains, result);
1878 return result;
1758 - } else if (node.type === 'ChainExpression' && !node.computed) {
1879 + } else if (
1880 + node.type === 'ChainExpression' &&
1881 + (!('computed' in node) || !node.computed)
1882 + ) {
1883 const expression = node.expression;
1884
1885 if (expression.type === 'CallExpression') {
@@ -1772,7 +1896,9 @@ function analyzePropertyChain(node, optionalChains) {
1896 }
1897 }
1898
1775 -function getNodeWithoutReactNamespace(node, options) {
1899 +function getNodeWithoutReactNamespace(
1900 + node: Expression | Super,
1901 +): Expression | Identifier | Super {
1902 if (
1903 node.type === 'MemberExpression' &&
1904 node.object.type === 'Identifier' &&
@@ -1790,7 +1916,13 @@ function getNodeWithoutReactNamespace(node, options) {
1916 // 0 for useEffect/useMemo/useCallback(fn).
1917 // 1 for useImperativeHandle(ref, fn).
1918 // For additionally configured Hooks, assume that they're like useEffect (0).
1793 -function getReactiveHookCallbackIndex(calleeNode, options) {
1919 +function getReactiveHookCallbackIndex(
1920 + calleeNode: Expression | Super,
1921 + options?: {
1922 + additionalHooks: RegExp | undefined;
1923 + enableDangerousAutofixThisMayCauseInfiniteLoops?: boolean;
1924 + },
1925 +): 0 | -1 | 1 {
1926 const node = getNodeWithoutReactNamespace(calleeNode);
1927 if (node.type !== 'Identifier') {
1928 return -1;
@@ -1812,8 +1944,11 @@ function getReactiveHookCallbackIndex(calleeNode, options) {
1944 let name;
1945 try {
1946 name = analyzePropertyChain(node, null);
1815 - } catch (error) {
1816 - if (/Unsupported node type/.test(error.message)) {
1947 + } catch (error: unknown) {
1948 + if (
1949 + error instanceof Error &&
1950 + /Unsupported node type/.test(error.message)
1951 + ) {
1952 return 0;
1953 } else {
1954 throw error;
@@ -1836,12 +1971,12 @@ function getReactiveHookCallbackIndex(calleeNode, options) {
1971 * - optimized by only searching nodes with a range surrounding our target node
1972 * - agnostic to AST node types, it looks for `{ type: string, ... }`
1973 */
1839 -function fastFindReferenceWithParent(start, target) {
1974 +function fastFindReferenceWithParent(start: Node, target: Node): Node | null {
1975 const queue = [start];
1841 - let item = null;
1976 + let item: Node;
1977
1978 while (queue.length) {
1844 - item = queue.shift();
1979 + item = queue.shift() as Node;
1980
1981 if (isSameIdentifier(item, target)) {
1982 return item;
@@ -1872,7 +2007,7 @@ function fastFindReferenceWithParent(start, target) {
2007 return null;
2008 }
2009
1875 -function joinEnglish(arr) {
2010 +function joinEnglish(arr: string[]): string {
2011 let s = '';
2012 for (let i = 0; i < arr.length; i++) {
2013 s += arr[i];
@@ -1887,39 +2022,49 @@ function joinEnglish(arr) {
2022 return s;
2023 }
2024
1890 -function isNodeLike(val) {
2025 +function isNodeLike(val: unknown): boolean {
2026 return (
2027 typeof val === 'object' &&
2028 val !== null &&
2029 !Array.isArray(val) &&
2030 + 'type' in val &&
2031 typeof val.type === 'string'
2032 );
2033 }
2034
1899 -function isSameIdentifier(a, b) {
2035 +function isSameIdentifier(a: Node, b: Node): boolean {
2036 return (
2037 (a.type === 'Identifier' || a.type === 'JSXIdentifier') &&
2038 a.type === b.type &&
2039 a.name === b.name &&
2040 + !!a.range &&
2041 + !!b.range &&
2042 a.range[0] === b.range[0] &&
2043 a.range[1] === b.range[1]
2044 );
2045 }
2046
1909 -function isAncestorNodeOf(a, b) {
1910 - return a.range[0] <= b.range[0] && a.range[1] >= b.range[1];
2047 +function isAncestorNodeOf(a: Node, b: Node): boolean {
2048 + return (
2049 + !!a.range &&
2050 + !!b.range &&
2051 + a.range[0] <= b.range[0] &&
2052 + a.range[1] >= b.range[1]
2053 + );
2054 }
2055
1913 -function isUseEffectEventIdentifier(node) {
2056 +function isUseEffectEventIdentifier(node: Node): boolean {
2057 if (__EXPERIMENTAL__) {
2058 return node.type === 'Identifier' && node.name === 'useEffectEvent';
2059 }
2060 return false;
2061 }
2062
1920 -function getUnknownDependenciesMessage(reactiveHookName) {
2063 +function getUnknownDependenciesMessage(reactiveHookName: string): string {
2064 return (
2065 `React Hook ${reactiveHookName} received a function whose dependencies ` +
2066 `are unknown. Pass an inline function instead.`
2067 );
2068 }
2069 +
2070 +export default rule;
packages/eslint-plugin-react-hooks/src/RulesOfHooks.ts renamed
+81 -64
@@ -4,18 +4,16 @@
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7 -
8 -/* global BigInt */
7 /* eslint-disable no-for-of-loops/no-for-of-loops */
8
11 -'use strict';
9 +import type {Rule, Scope} from 'eslint';
10 +import type {CallExpression, DoWhileStatement, Node} from 'estree';
11
12 /**
13 * Catch all identifiers that begin with "use" followed by an uppercase Latin
14 * character to exclude identifiers like "user".
15 */
17 -
18 -function isHookName(s) {
16 +function isHookName(s: string): boolean {
17 return s === 'use' || /^use[A-Z0-9]/.test(s);
18 }
19
@@ -23,8 +21,7 @@ function isHookName(s) {
21 * We consider hooks to be a hook name identifier or a member expression
22 * containing a hook name.
23 */
26 -
27 -function isHook(node) {
24 +function isHook(node: Node): boolean {
25 if (node.type === 'Identifier') {
26 return isHookName(node.name);
27 } else if (
@@ -44,16 +41,17 @@ function isHook(node) {
41 * Checks if the node is a React component name. React component names must
42 * always start with an uppercase letter.
43 */
47 -
48 -function isComponentName(node) {
44 +function isComponentName(node: Node): boolean {
45 return node.type === 'Identifier' && /^[A-Z]/.test(node.name);
46 }
47
52 -function isReactFunction(node, functionName) {
48 +function isReactFunction(node: Node, functionName: string): boolean {
49 return (
54 - node.name === functionName ||
50 + ('name' in node && node.name === functionName) ||
51 (node.type === 'MemberExpression' &&
52 + 'name' in node.object &&
53 node.object.name === 'React' &&
54 + 'name' in node.property &&
55 node.property.name === functionName)
56 );
57 }
@@ -62,10 +60,10 @@ function isReactFunction(node, functionName) {
60 * Checks if the node is a callback argument of forwardRef. This render function
61 * should follow the rules of hooks.
62 */
65 -
66 -function isForwardRefCallback(node) {
63 +function isForwardRefCallback(node: Node): boolean {
64 return !!(
65 node.parent &&
66 + 'callee' in node.parent &&
67 node.parent.callee &&
68 isReactFunction(node.parent.callee, 'forwardRef')
69 );
@@ -75,16 +73,16 @@ function isForwardRefCallback(node) {
73 * Checks if the node is a callback argument of React.memo. This anonymous
74 * functional component should follow the rules of hooks.
75 */
78 -
79 -function isMemoCallback(node) {
76 +function isMemoCallback(node: Node): boolean {
77 return !!(
78 node.parent &&
79 + 'callee' in node.parent &&
80 node.parent.callee &&
81 isReactFunction(node.parent.callee, 'memo')
82 );
83 }
84
87 -function isInsideComponentOrHook(node) {
85 +function isInsideComponentOrHook(node: Node | undefined): boolean {
86 while (node) {
87 const functionName = getFunctionName(node);
88 if (functionName) {
@@ -100,7 +98,7 @@ function isInsideComponentOrHook(node) {
98 return false;
99 }
100
103 -function isInsideDoWhileLoop(node) {
101 +function isInsideDoWhileLoop(node: Node | undefined): node is DoWhileStatement {
102 while (node) {
103 if (node.type === 'DoWhileStatement') {
104 return true;
@@ -110,18 +108,18 @@ function isInsideDoWhileLoop(node) {
108 return false;
109 }
110
113 -function isUseEffectEventIdentifier(node) {
111 +function isUseEffectEventIdentifier(node: Node): boolean {
112 if (__EXPERIMENTAL__) {
113 return node.type === 'Identifier' && node.name === 'useEffectEvent';
114 }
115 return false;
116 }
117
120 -function isUseIdentifier(node) {
118 +function isUseIdentifier(node: Node): boolean {
119 return isReactFunction(node, 'use');
120 }
121
124 -export default {
122 +const rule = {
123 meta: {
124 type: 'problem',
125 docs: {
@@ -130,25 +128,28 @@ export default {
128 url: 'https://reactjs.org/docs/hooks-rules.html',
129 },
130 },
133 - create(context) {
134 - let lastEffect = null;
135 - const codePathReactHooksMapStack = [];
136 - const codePathSegmentStack = [];
131 + create(context: Rule.RuleContext) {
132 + let lastEffect: CallExpression | null = null;
133 + const codePathReactHooksMapStack: Map<Rule.CodePathSegment, Node[]>[] = [];
134 + const codePathSegmentStack: Rule.CodePathSegment[] = [];
135 const useEffectEventFunctions = new WeakSet();
136
137 // For a given scope, iterate through the references and add all useEffectEvent definitions. We can
138 // do this in non-Program nodes because we can rely on the assumption that useEffectEvent functions
139 // can only be declared within a component or hook at its top level.
142 - function recordAllUseEffectEventFunctions(scope) {
140 + function recordAllUseEffectEventFunctions(scope: Scope.Scope): void {
141 for (const reference of scope.references) {
142 const parent = reference.identifier.parent;
143 if (
146 - parent.type === 'VariableDeclarator' &&
144 + parent?.type === 'VariableDeclarator' &&
145 parent.init &&
146 parent.init.type === 'CallExpression' &&
147 parent.init.callee &&
148 isUseEffectEventIdentifier(parent.init.callee)
149 ) {
150 + if (reference.resolved === null) {
151 + throw new Error('Unexpected null reference.resolved');
152 + }
153 for (const ref of reference.resolved.references) {
154 if (ref !== reference) {
155 useEffectEventFunctions.add(ref.identifier);
@@ -159,26 +160,26 @@ export default {
160 }
161
162 /**
162 - * SourceCode#getText that also works down to ESLint 3.0.0
163 + * SourceCode that also works down to ESLint 3.0.0
164 */
164 - const getSource =
165 - typeof context.getSource === 'function'
166 - ? node => {
167 - return context.getSource(node);
165 + const getSourceCode =
166 + typeof context.getSourceCode === 'function'
167 + ? () => {
168 + return context.getSourceCode();
169 }
169 - : node => {
170 - return context.sourceCode.getText(node);
170 + : () => {
171 + return context.sourceCode;
172 };
173 /**
174 * SourceCode#getScope that also works down to ESLint 3.0.0
175 */
176 const getScope =
177 typeof context.getScope === 'function'
177 - ? () => {
178 + ? (): Scope.Scope => {
179 return context.getScope();
180 }
180 - : node => {
181 - return context.sourceCode.getScope(node);
181 + : (node: Node): Scope.Scope => {
182 + return getSourceCode().getScope(node);
183 };
184
185 return {
@@ -187,7 +188,10 @@ export default {
188 onCodePathSegmentEnd: () => codePathSegmentStack.pop(),
189
190 // Maintain code path stack as we traverse.
190 - onCodePathStart: () => codePathReactHooksMapStack.push(new Map()),
191 + onCodePathStart: () =>
192 + codePathReactHooksMapStack.push(
193 + new Map<Rule.CodePathSegment, Node[]>(),
194 + ),
195
196 // Process our code path.
197 //
@@ -195,8 +199,10 @@ export default {
199 // segment and reachable from every final segment.
200 onCodePathEnd(codePath, codePathNode) {
201 const reactHooksMap = codePathReactHooksMapStack.pop();
198 - if (reactHooksMap.size === 0) {
202 + if (reactHooksMap?.size === 0) {
203 return;
204 + } else if (typeof reactHooksMap === 'undefined') {
205 + throw new Error('Unexpected undefined reactHooksMap');
206 }
207
208 // All of the segments which are cyclic are recorded in this set.
@@ -223,11 +229,13 @@ export default {
229 *
230 * Populates `cyclic` with cyclic segments.
231 */
226 -
227 - function countPathsFromStart(segment, pathHistory) {
232 + function countPathsFromStart(
233 + segment: Rule.CodePathSegment,
234 + pathHistory?: Set<string>,
235 + ): bigint {
236 const {cache} = countPathsFromStart;
237 let paths = cache.get(segment.id);
230 - const pathList = new Set(pathHistory);
238 + const pathList = new Set<string>(pathHistory);
239
240 // If `pathList` includes the current segment then we've found a cycle!
241 // We need to fill `cyclic` with all segments inside cycle
@@ -295,7 +303,10 @@ export default {
303 * Populates `cyclic` with cyclic segments.
304 */
305
298 - function countPathsToEnd(segment, pathHistory) {
306 + function countPathsToEnd(
307 + segment: Rule.CodePathSegment,
308 + pathHistory?: Set<string>,
309 + ): bigint {
310 const {cache} = countPathsToEnd;
311 let paths = cache.get(segment.id);
312 const pathList = new Set(pathHistory);
@@ -359,7 +370,9 @@ export default {
370 * so we would return that.
371 */
372
362 - function shortestPathLengthToStart(segment) {
373 + function shortestPathLengthToStart(
374 + segment: Rule.CodePathSegment,
375 + ): number {
376 const {cache} = shortestPathLengthToStart;
377 let length = cache.get(segment.id);
378
@@ -392,9 +405,9 @@ export default {
405 return length;
406 }
407
395 - countPathsFromStart.cache = new Map();
396 - countPathsToEnd.cache = new Map();
397 - shortestPathLengthToStart.cache = new Map();
408 + countPathsFromStart.cache = new Map<string, bigint>();
409 + countPathsToEnd.cache = new Map<string, bigint>();
410 + shortestPathLengthToStart.cache = new Map<string, number | null>();
411
412 // Count all code paths to the end of our component/hook. Also primes
413 // the `countPathsToEnd` cache.
@@ -502,7 +515,7 @@ export default {
515 context.report({
516 node: hook,
517 message:
505 - `React Hook "${getSource(hook)}" may be executed ` +
518 + `React Hook "${getSourceCode().getText(hook)}" may be executed ` +
519 'more than once. Possibly because it is called in a loop. ' +
520 'React Hooks must be called in the exact same order in ' +
521 'every component render.',
@@ -516,12 +529,13 @@ export default {
529 // called in.
530 if (isDirectlyInsideComponentOrHook) {
531 // Report an error if the hook is called inside an async function.
532 + // @ts-expect-error the above check hasn't properly type-narrowed `codePathNode` (async doesn't exist on Node)
533 const isAsyncFunction = codePathNode.async;
534 if (isAsyncFunction) {
535 context.report({
536 node: hook,
537 message:
524 - `React Hook "${getSource(hook)}" cannot be ` +
538 + `React Hook "${getSourceCode().getText(hook)}" cannot be ` +
539 'called in an async function.',
540 });
541 }
@@ -537,7 +551,7 @@ export default {
551 !isInsideDoWhileLoop(hook) // wrapping do/while loops are checked separately.
552 ) {
553 const message =
540 - `React Hook "${getSource(hook)}" is called ` +
554 + `React Hook "${getSourceCode().getText(hook)}" is called ` +
555 'conditionally. React Hooks must be called in the exact ' +
556 'same order in every component render.' +
557 (possiblyHasEarlyReturn
@@ -549,21 +563,22 @@ export default {
563 } else if (
564 codePathNode.parent &&
565 (codePathNode.parent.type === 'MethodDefinition' ||
566 + // @ts-expect-error `ClassProperty` was removed from typescript-estree in https://github.com/typescript-eslint/typescript-eslint/pull/3806
567 codePathNode.parent.type === 'ClassProperty' ||
568 codePathNode.parent.type === 'PropertyDefinition') &&
569 codePathNode.parent.value === codePathNode
570 ) {
571 // Custom message for hooks inside a class
572 const message =
558 - `React Hook "${getSource(hook)}" cannot be called ` +
573 + `React Hook "${getSourceCode().getText(hook)}" cannot be called ` +
574 'in a class component. React Hooks must be called in a ' +
575 'React function component or a custom React Hook function.';
576 context.report({node: hook, message});
577 } else if (codePathFunctionName) {
578 // Custom message if we found an invalid function name.
579 const message =
565 - `React Hook "${getSource(hook)}" is called in ` +
566 - `function "${getSource(codePathFunctionName)}" ` +
580 + `React Hook "${getSourceCode().getText(hook)}" is called in ` +
581 + `function "${getSourceCode().getText(codePathFunctionName)}" ` +
582 'that is neither a React function component nor a custom ' +
583 'React Hook function.' +
584 ' React component names must start with an uppercase letter.' +
@@ -572,7 +587,7 @@ export default {
587 } else if (codePathNode.type === 'Program') {
588 // These are dangerous if you have inline requires enabled.
589 const message =
575 - `React Hook "${getSource(hook)}" cannot be called ` +
590 + `React Hook "${getSourceCode().getText(hook)}" cannot be called ` +
591 'at the top level. React Hooks must be called in a ' +
592 'React function component or a custom React Hook function.';
593 context.report({node: hook, message});
@@ -585,7 +600,7 @@ export default {
600 // `use(...)` can be called in callbacks.
601 if (isSomewhereInsideComponentOrHook && !isUseIdentifier(hook)) {
602 const message =
588 - `React Hook "${getSource(hook)}" cannot be called ` +
603 + `React Hook "${getSourceCode().getText(hook)}" cannot be called ` +
604 'inside a callback. React Hooks must be called in a ' +
605 'React function component or a custom React Hook function.';
606 context.report({node: hook, message});
@@ -638,7 +653,7 @@ export default {
653 context.report({
654 node,
655 message:
641 - `\`${getSource(
656 + `\`${getSourceCode().getText(
657 node,
658 )}\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
659 'the same component. They cannot be assigned to variables or passed down.',
@@ -667,7 +682,7 @@ export default {
682 },
683 };
684 },
670 -};
685 +} satisfies Rule.RuleModule;
686
687 /**
688 * Gets the static name of a function AST node. For function declarations it is
@@ -677,7 +692,7 @@ export default {
692 * same AST nodes with some exceptions to better fit our use case.
693 */
694
680 -function getFunctionName(node) {
695 +function getFunctionName(node: Node) {
696 if (
697 node.type === 'FunctionDeclaration' ||
698 (node.type === 'FunctionExpression' && node.id)
@@ -693,20 +708,20 @@ function getFunctionName(node) {
708 node.type === 'ArrowFunctionExpression'
709 ) {
710 if (
696 - node.parent.type === 'VariableDeclarator' &&
711 + node.parent?.type === 'VariableDeclarator' &&
712 node.parent.init === node
713 ) {
714 // const useHook = () => {};
715 return node.parent.id;
716 } else if (
702 - node.parent.type === 'AssignmentExpression' &&
717 + node.parent?.type === 'AssignmentExpression' &&
718 node.parent.right === node &&
719 node.parent.operator === '='
720 ) {
721 // useHook = () => {};
722 return node.parent.left;
723 } else if (
709 - node.parent.type === 'Property' &&
724 + node.parent?.type === 'Property' &&
725 node.parent.value === node &&
726 !node.parent.computed
727 ) {
@@ -721,8 +736,9 @@ function getFunctionName(node) {
736 // class {useHook = () => {}}
737 // class {useHook() {}}
738 } else if (
724 - node.parent.type === 'AssignmentPattern' &&
739 + node.parent?.type === 'AssignmentPattern' &&
740 node.parent.right === node &&
741 + // @ts-expect-error Property computed does not exist on type `AssignmentPattern`.
742 !node.parent.computed
743 ) {
744 // const {useHook = () => {}} = {};
@@ -742,7 +758,8 @@ function getFunctionName(node) {
758 /**
759 * Convenience function for peeking the last item in a stack.
760 */
745 -
746 -function last(array) {
747 - return array[array.length - 1];
761 +function last<T>(array: T[]): T {
762 + return array[array.length - 1] as T;
763 }
764 +
765 +export default rule;
packages/eslint-plugin-react-hooks/src/index.js deleted
-61
@@ -1,61 +0,0 @@
1 -/**
2 - * Copyright (c) Meta Platforms, Inc. and affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - */
7 -
8 -'use strict';
9 -
10 -import RulesOfHooks from './RulesOfHooks';
11 -import ExhaustiveDeps from './ExhaustiveDeps';
12 -
13 -// All rules
14 -export const rules = {
15 - 'rules-of-hooks': RulesOfHooks,
16 - 'exhaustive-deps': ExhaustiveDeps,
17 -};
18 -
19 -// Config rules
20 -const configRules = {
21 - 'react-hooks/rules-of-hooks': 'error',
22 - 'react-hooks/exhaustive-deps': 'warn',
23 -};
24 -
25 -// Legacy config
26 -const legacyRecommendedConfig = {
27 - plugins: ['react-hooks'],
28 - rules: configRules,
29 -};
30 -
31 -// Base plugin object
32 -const reactHooksPlugin = {
33 - meta: {name: 'eslint-plugin-react-hooks'},
34 - rules,
35 -};
36 -
37 -// Flat config
38 -const flatRecommendedConfig = {
39 - name: 'react-hooks/recommended',
40 - plugins: {'react-hooks': reactHooksPlugin},
41 - rules: configRules,
42 -};
43 -
44 -export const configs = {
45 - /** Legacy recommended config, to be used with rc-based configurations */
46 - 'recommended-legacy': legacyRecommendedConfig,
47 -
48 - /** Latest recommended config, to be used with flat configurations */
49 - 'recommended-latest': flatRecommendedConfig,
50 -
51 - /**
52 - * 'recommended' is currently aliased to the legacy / rc recommended config) to maintain backwards compatibility.
53 - * This is deprecated and in v6, it will switch to alias the flat recommended config.
54 - */
55 - recommended: legacyRecommendedConfig,
56 -};
57 -
58 -export default {
59 - ...reactHooksPlugin,
60 - configs,
61 -};
packages/eslint-plugin-react-hooks/src/index.ts new
+64
@@ -0,0 +1,64 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +import RulesOfHooks from './RulesOfHooks';
8 +import ExhaustiveDeps from './ExhaustiveDeps';
9 +import type {ESLint, Linter, Rule} from 'eslint';
10 +
11 +// All rules
12 +const rules = {
13 + 'rules-of-hooks': RulesOfHooks,
14 + 'exhaustive-deps': ExhaustiveDeps,
15 +} satisfies Record<string, Rule.RuleModule>;
16 +
17 +// Config rules
18 +const configRules = {
19 + 'react-hooks/rules-of-hooks': 'error',
20 + 'react-hooks/exhaustive-deps': 'warn',
21 +} satisfies Linter.RulesRecord;
22 +
23 +// Legacy config
24 +const legacyRecommendedConfig = {
25 + plugins: ['react-hooks'],
26 + rules: configRules,
27 +} satisfies Linter.LegacyConfig;
28 +
29 +// Plugin object
30 +const plugin = {
31 + // TODO: Make this more dynamic to populate version from package.json.
32 + // This can be done by injecting at build time, since importing the package.json isn't an option in Meta
33 + meta: {name: 'eslint-plugin-react-hooks'},
34 + rules,
35 + configs: {
36 + /** Legacy recommended config, to be used with rc-based configurations */
37 + 'recommended-legacy': legacyRecommendedConfig,
38 +
39 + /**
40 + * 'recommended' is currently aliased to the legacy / rc recommended config) to maintain backwards compatibility.
41 + * This is deprecated and in v6, it will switch to alias the flat recommended config.
42 + */
43 + recommended: legacyRecommendedConfig,
44 +
45 + /** Latest recommended config, to be used with flat configurations */
46 + 'recommended-latest': {
47 + name: 'react-hooks/recommended',
48 + plugins: {
49 + get 'react-hooks'(): ESLint.Plugin {
50 + return plugin;
51 + },
52 + },
53 + rules: configRules,
54 + },
55 + },
56 +} satisfies ESLint.Plugin;
57 +
58 +const configs = plugin.configs;
59 +const meta = plugin.meta;
60 +export {configs, meta, rules};
61 +
62 +// 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
63 +// instead of individual named exports.
64 +// export default plugin;
packages/eslint-plugin-react-hooks/src/types/estree.d.ts
+2
@@ -1,3 +1,5 @@
1 +import {Expression, Identifier, Node} from 'estree-jsx';
2 +
3 /**
4 * This file augments the `estree` types to include types that are not built-in to `estree` or `estree-jsx`.
5 * This is necessary because the `estree` types are used by ESLint, and ESLint does not natively support
packages/eslint-plugin-react-hooks/tsconfig.json
-1
@@ -6,7 +6,6 @@
6 "moduleResolution": "Bundler",
7 "lib": ["ES2020"],
8 "rootDir": ".",
9 - "noEmit": true,
9 "sourceMap": false,
10 "types": ["estree-jsx", "node"]
11 },
packages/eslint-plugin-react-hooks/tsup.config.ts deleted
-9
@@ -1,9 +0,0 @@
1 -import {defineConfig} from 'tsup';
2 -
3 -export default defineConfig({
4 - clean: true,
5 - dts: true,
6 - entry: ['src/index.ts'],
7 - format: ['cjs'],
8 - outDir: 'build',
9 -});
scripts/rollup/bundles.js
+8 -6
@@ -1184,17 +1184,19 @@ const bundles = [
1184
1185 /******* ESLint Plugin for Hooks *******/
1186 {
1187 - // TODO: it's awkward to create a bundle for this but if we don't, the package
1188 - // won't get copied. We also can't create just DEV bundle because it contains a
1189 - // NODE_ENV check inside. We should probably tweak our build process to allow
1190 - // "raw" packages that don't get bundled.
1191 - bundleTypes: [NODE_DEV, NODE_PROD],
1187 + // TODO: we're building this from typescript source now, but there's really
1188 + // no reason to have both dev and prod for this package. It's
1189 + // currently required in order for the package to be copied over correctly.
1190 + // So, it would be worth improving that flow.
1191 + name: 'eslint-plugin-react-hooks',
1192 + bundleTypes: [NODE_DEV, NODE_PROD, CJS_DTS],
1193 moduleType: ISOMORPHIC,
1193 - entry: 'eslint-plugin-react-hooks',
1194 + entry: 'eslint-plugin-react-hooks/src/index.ts',
1195 global: 'ESLintPluginReactHooks',
1196 minifyWithProdErrorCodes: false,
1197 wrapWithModuleBoundaries: false,
1198 externals: [],
1199 + tsconfig: './packages/eslint-plugin-react-hooks/tsconfig.json',
1200 },
1201
1202 /******* React Fresh *******/
yarn.lock
+4 -463
@@ -2403,131 +2403,6 @@
2403 opn "5.3.0"
2404 react "^16.13.1"
2405
2406 -"@esbuild/aix-ppc64@0.24.2":
2407 - version "0.24.2"
2408 - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz#38848d3e25afe842a7943643cbcd387cc6e13461"
2409 - integrity sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==
2410 -
2411 -"@esbuild/android-arm64@0.24.2":
2412 - version "0.24.2"
2413 - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz#f592957ae8b5643129fa889c79e69cd8669bb894"
2414 - integrity sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==
2415 -
2416 -"@esbuild/android-arm@0.24.2":
2417 - version "0.24.2"
2418 - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.24.2.tgz#72d8a2063aa630308af486a7e5cbcd1e134335b3"
2419 - integrity sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==
2420 -
2421 -"@esbuild/android-x64@0.24.2":
2422 - version "0.24.2"
2423 - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.24.2.tgz#9a7713504d5f04792f33be9c197a882b2d88febb"
2424 - integrity sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==
2425 -
2426 -"@esbuild/darwin-arm64@0.24.2":
2427 - version "0.24.2"
2428 - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz#02ae04ad8ebffd6e2ea096181b3366816b2b5936"
2429 - integrity sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==
2430 -
2431 -"@esbuild/darwin-x64@0.24.2":
2432 - version "0.24.2"
2433 - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz#9ec312bc29c60e1b6cecadc82bd504d8adaa19e9"
2434 - integrity sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==
2435 -
2436 -"@esbuild/freebsd-arm64@0.24.2":
2437 - version "0.24.2"
2438 - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz#5e82f44cb4906d6aebf24497d6a068cfc152fa00"
2439 - integrity sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==
2440 -
2441 -"@esbuild/freebsd-x64@0.24.2":
2442 - version "0.24.2"
2443 - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz#3fb1ce92f276168b75074b4e51aa0d8141ecce7f"
2444 - integrity sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==
2445 -
2446 -"@esbuild/linux-arm64@0.24.2":
2447 - version "0.24.2"
2448 - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz#856b632d79eb80aec0864381efd29de8fd0b1f43"
2449 - integrity sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==
2450 -
2451 -"@esbuild/linux-arm@0.24.2":
2452 - version "0.24.2"
2453 - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz#c846b4694dc5a75d1444f52257ccc5659021b736"
2454 - integrity sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==
2455 -
2456 -"@esbuild/linux-ia32@0.24.2":
2457 - version "0.24.2"
2458 - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz#f8a16615a78826ccbb6566fab9a9606cfd4a37d5"
2459 - integrity sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==
2460 -
2461 -"@esbuild/linux-loong64@0.24.2":
2462 - version "0.24.2"
2463 - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz#1c451538c765bf14913512c76ed8a351e18b09fc"
2464 - integrity sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==
2465 -
2466 -"@esbuild/linux-mips64el@0.24.2":
2467 - version "0.24.2"
2468 - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz#0846edeefbc3d8d50645c51869cc64401d9239cb"
2469 - integrity sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==
2470 -
2471 -"@esbuild/linux-ppc64@0.24.2":
2472 - version "0.24.2"
2473 - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz#8e3fc54505671d193337a36dfd4c1a23b8a41412"
2474 - integrity sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==
2475 -
2476 -"@esbuild/linux-riscv64@0.24.2":
2477 - version "0.24.2"
2478 - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz#6a1e92096d5e68f7bb10a0d64bb5b6d1daf9a694"
2479 - integrity sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==
2480 -
2481 -"@esbuild/linux-s390x@0.24.2":
2482 - version "0.24.2"
2483 - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz#ab18e56e66f7a3c49cb97d337cd0a6fea28a8577"
2484 - integrity sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==
2485 -
2486 -"@esbuild/linux-x64@0.24.2":
2487 - version "0.24.2"
2488 - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz#8140c9b40da634d380b0b29c837a0b4267aff38f"
2489 - integrity sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==
2490 -
2491 -"@esbuild/netbsd-arm64@0.24.2":
2492 - version "0.24.2"
2493 - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz#65f19161432bafb3981f5f20a7ff45abb2e708e6"
2494 - integrity sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==
2495 -
2496 -"@esbuild/netbsd-x64@0.24.2":
2497 - version "0.24.2"
2498 - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz#7a3a97d77abfd11765a72f1c6f9b18f5396bcc40"
2499 - integrity sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==
2500 -
2501 -"@esbuild/openbsd-arm64@0.24.2":
2502 - version "0.24.2"
2503 - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz#58b00238dd8f123bfff68d3acc53a6ee369af89f"
2504 - integrity sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==
2505 -
2506 -"@esbuild/openbsd-x64@0.24.2":
2507 - version "0.24.2"
2508 - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz#0ac843fda0feb85a93e288842936c21a00a8a205"
2509 - integrity sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==
2510 -
2511 -"@esbuild/sunos-x64@0.24.2":
2512 - version "0.24.2"
2513 - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz#8b7aa895e07828d36c422a4404cc2ecf27fb15c6"
2514 - integrity sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==
2515 -
2516 -"@esbuild/win32-arm64@0.24.2":
2517 - version "0.24.2"
2518 - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz#c023afb647cabf0c3ed13f0eddfc4f1d61c66a85"
2519 - integrity sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==
2520 -
2521 -"@esbuild/win32-ia32@0.24.2":
2522 - version "0.24.2"
2523 - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz#96c356132d2dda990098c8b8b951209c3cd743c2"
2524 - integrity sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==
2525 -
2526 -"@esbuild/win32-x64@0.24.2":
2527 - version "0.24.2"
2528 - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz#34aa0b52d0fbb1a654b596acfa595f0c7b77a77b"
2529 - integrity sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==
2530 -
2406 "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
2407 version "4.4.0"
2408 resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@@ -2924,15 +2799,6 @@
2799 "@jridgewell/sourcemap-codec" "^1.4.10"
2800 "@jridgewell/trace-mapping" "^0.3.9"
2801
2927 -"@jridgewell/gen-mapping@^0.3.2":
2928 - version "0.3.8"
2929 - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142"
2930 - integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==
2931 - dependencies:
2932 - "@jridgewell/set-array" "^1.2.1"
2933 - "@jridgewell/sourcemap-codec" "^1.4.10"
2934 - "@jridgewell/trace-mapping" "^0.3.24"
2935 -
2802 "@jridgewell/gen-mapping@^0.3.5":
2803 version "0.3.5"
2804 resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
@@ -3396,101 +3262,6 @@
3262 estree-walker "^2.0.2"
3263 picomatch "^4.0.2"
3264
3399 -"@rollup/rollup-android-arm-eabi@4.34.7":
3400 - version "4.34.7"
3401 - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.7.tgz#e554185b1afa5509a7a4040d15ec0c3b4435ded1"
3402 - integrity sha512-l6CtzHYo8D2TQ3J7qJNpp3Q1Iye56ssIAtqbM2H8axxCEEwvN7o8Ze9PuIapbxFL3OHrJU2JBX6FIIVnP/rYyw==
3403 -
3404 -"@rollup/rollup-android-arm64@4.34.7":
3405 - version "4.34.7"
3406 - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.7.tgz#b1ee64bb413b2feba39803b0a1bebf2a9f3d70e1"
3407 - integrity sha512-KvyJpFUueUnSp53zhAa293QBYqwm94TgYTIfXyOTtidhm5V0LbLCJQRGkQClYiX3FXDQGSvPxOTD/6rPStMMDg==
3408 -
3409 -"@rollup/rollup-darwin-arm64@4.34.7":
3410 - version "4.34.7"
3411 - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.7.tgz#bfdce3e07a345dd1bd628f3b796050f39629d7f0"
3412 - integrity sha512-jq87CjmgL9YIKvs8ybtIC98s/M3HdbqXhllcy9EdLV0yMg1DpxES2gr65nNy7ObNo/vZ/MrOTxt0bE5LinL6mA==
3413 -
3414 -"@rollup/rollup-darwin-x64@4.34.7":
3415 - version "4.34.7"
3416 - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.7.tgz#781a94a537c57bdf0a500e47a25ab5985e5e8dff"
3417 - integrity sha512-rSI/m8OxBjsdnMMg0WEetu/w+LhLAcCDEiL66lmMX4R3oaml3eXz3Dxfvrxs1FbzPbJMaItQiksyMfv1hoIxnA==
3418 -
3419 -"@rollup/rollup-freebsd-arm64@4.34.7":
3420 - version "4.34.7"
3421 - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.7.tgz#7a028357cbd12c5869c446ad18177c89f3405102"
3422 - integrity sha512-oIoJRy3ZrdsXpFuWDtzsOOa/E/RbRWXVokpVrNnkS7npz8GEG++E1gYbzhYxhxHbO2om1T26BZjVmdIoyN2WtA==
3423 -
3424 -"@rollup/rollup-freebsd-x64@4.34.7":
3425 - version "4.34.7"
3426 - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.7.tgz#f24836a6371cccc4408db74f0fd986dacf098950"
3427 - integrity sha512-X++QSLm4NZfZ3VXGVwyHdRf58IBbCu9ammgJxuWZYLX0du6kZvdNqPwrjvDfwmi6wFdvfZ/s6K7ia0E5kI7m8Q==
3428 -
3429 -"@rollup/rollup-linux-arm-gnueabihf@4.34.7":
3430 - version "4.34.7"
3431 - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.7.tgz#95f27e96f0eb9b9ae9887739a8b6dffc90c1237f"
3432 - integrity sha512-Z0TzhrsNqukTz3ISzrvyshQpFnFRfLunYiXxlCRvcrb3nvC5rVKI+ZXPFG/Aa4jhQa1gHgH3A0exHaRRN4VmdQ==
3433 -
3434 -"@rollup/rollup-linux-arm-musleabihf@4.34.7":
3435 - version "4.34.7"
3436 - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.7.tgz#677b34fba9d070877736c3fe8b02aacb5e142d97"
3437 - integrity sha512-nkznpyXekFAbvFBKBy4nNppSgneB1wwG1yx/hujN3wRnhnkrYVugMTCBXED4+Ni6thoWfQuHNYbFjgGH0MBXtw==
3438 -
3439 -"@rollup/rollup-linux-arm64-gnu@4.34.7":
3440 - version "4.34.7"
3441 - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.7.tgz#32d3d19dedde54e91574a098f22ea43a09cf63dd"
3442 - integrity sha512-KCjlUkcKs6PjOcxolqrXglBDcfCuUCTVlX5BgzgoJHw+1rWH1MCkETLkLe5iLLS9dP5gKC7mp3y6x8c1oGBUtA==
3443 -
3444 -"@rollup/rollup-linux-arm64-musl@4.34.7":
3445 - version "4.34.7"
3446 - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.7.tgz#a58dff44a18696df65ed8c0ad68a2945cf900484"
3447 - integrity sha512-uFLJFz6+utmpbR313TTx+NpPuAXbPz4BhTQzgaP0tozlLnGnQ6rCo6tLwaSa6b7l6gRErjLicXQ1iPiXzYotjw==
3448 -
3449 -"@rollup/rollup-linux-loongarch64-gnu@4.34.7":
3450 - version "4.34.7"
3451 - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.7.tgz#a7488ab078233111e8aeb370d1ecf107ec7e1716"
3452 - integrity sha512-ws8pc68UcJJqCpneDFepnwlsMUFoWvPbWXT/XUrJ7rWUL9vLoIN3GAasgG+nCvq8xrE3pIrd+qLX/jotcLy0Qw==
3453 -
3454 -"@rollup/rollup-linux-powerpc64le-gnu@4.34.7":
3455 - version "4.34.7"
3456 - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.7.tgz#e9b9c0d6bd248a92b2d6ec01ebf99c62ae1f2e9a"
3457 - integrity sha512-vrDk9JDa/BFkxcS2PbWpr0C/LiiSLxFbNOBgfbW6P8TBe9PPHx9Wqbvx2xgNi1TOAyQHQJ7RZFqBiEohm79r0w==
3458 -
3459 -"@rollup/rollup-linux-riscv64-gnu@4.34.7":
3460 - version "4.34.7"
3461 - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.7.tgz#0df84ce2bea48ee686fb55060d76ab47aff45c4c"
3462 - integrity sha512-rB+ejFyjtmSo+g/a4eovDD1lHWHVqizN8P0Hm0RElkINpS0XOdpaXloqM4FBkF9ZWEzg6bezymbpLmeMldfLTw==
3463 -
3464 -"@rollup/rollup-linux-s390x-gnu@4.34.7":
3465 - version "4.34.7"
3466 - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.7.tgz#73df374c57d036856e33dbd2715138922e91e452"
3467 - integrity sha512-nNXNjo4As6dNqRn7OrsnHzwTgtypfRA3u3AKr0B3sOOo+HkedIbn8ZtFnB+4XyKJojIfqDKmbIzO1QydQ8c+Pw==
3468 -
3469 -"@rollup/rollup-linux-x64-gnu@4.34.7":
3470 - version "4.34.7"
3471 - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.7.tgz#f27af0b55f0cdd84e182e6cd44a6d03da0458149"
3472 - integrity sha512-9kPVf9ahnpOMSGlCxXGv980wXD0zRR3wyk8+33/MXQIpQEOpaNe7dEHm5LMfyRZRNt9lMEQuH0jUKj15MkM7QA==
3473 -
3474 -"@rollup/rollup-linux-x64-musl@4.34.7":
3475 - version "4.34.7"
3476 - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.7.tgz#c7981ad5cfb8c3cd5d643d33ca54e4d2802b9201"
3477 - integrity sha512-7wJPXRWTTPtTFDFezA8sle/1sdgxDjuMoRXEKtx97ViRxGGkVQYovem+Q8Pr/2HxiHp74SSRG+o6R0Yq0shPwQ==
3478 -
3479 -"@rollup/rollup-win32-arm64-msvc@4.34.7":
3480 - version "4.34.7"
3481 - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.7.tgz#06cedc0ef3cbf1cbd8abcf587090712e40ae6941"
3482 - integrity sha512-MN7aaBC7mAjsiMEZcsJvwNsQVNZShgES/9SzWp1HC9Yjqb5OpexYnRjF7RmE4itbeesHMYYQiAtUAQaSKs2Rfw==
3483 -
3484 -"@rollup/rollup-win32-ia32-msvc@4.34.7":
3485 - version "4.34.7"
3486 - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.7.tgz#90b39b977b14961a769be6ea61238e7fc668dd4d"
3487 - integrity sha512-aeawEKYswsFu1LhDM9RIgToobquzdtSc4jSVqHV8uApz4FVvhFl/mKh92wc8WpFc6aYCothV/03UjY6y7yLgbg==
3488 -
3489 -"@rollup/rollup-win32-x64-msvc@4.34.7":
3490 - version "4.34.7"
3491 - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.7.tgz#6531d61e7141091eaab0461ee8e0380c10e4ca57"
3492 - integrity sha512-4ZedScpxxIrVO7otcZ8kCX1mZArtH2Wfj3uFCxRJ9NO80gg1XV0U/b2f/MKaGwj2X3QopHfoWiDQ917FRpwY3w==
3493 -
3265 "@sinclair/typebox@^0.25.16":
3266 version "0.25.24"
3267 resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718"
@@ -3680,7 +3451,7 @@
3451 dependencies:
3452 "@types/estree" "*"
3453
3683 -"@types/estree@*", "@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.6":
3454 +"@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.6":
3455 version "1.0.6"
3456 resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50"
3457 integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==
@@ -5760,13 +5531,6 @@ bundle-name@^3.0.0:
5531 dependencies:
5532 run-applescript "^5.0.0"
5533
5763 -bundle-require@^5.0.0:
5764 - version "5.1.0"
5765 - resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-5.1.0.tgz#8db66f41950da3d77af1ef3322f4c3e04009faee"
5766 - integrity sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==
5767 - dependencies:
5768 - load-tsconfig "^0.2.3"
5769 -
5534 bunyan@1.8.15:
5535 version "1.8.15"
5536 resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.15.tgz#8ce34ca908a17d0776576ca1b2f6cbd916e93b46"
@@ -5787,11 +5551,6 @@ bytes@3.1.2:
5551 resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
5552 integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
5553
5790 -cac@^6.7.14:
5791 - version "6.7.14"
5792 - resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959"
5793 - integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
5794 -
5554 cache-base@^1.0.1:
5555 version "1.0.1"
5556 resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
@@ -6093,13 +5852,6 @@ chokidar@^3.5.3:
5852 optionalDependencies:
5853 fsevents "~2.3.2"
5854
6096 -chokidar@^4.0.1:
6097 - version "4.0.3"
6098 - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30"
6099 - integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==
6100 - dependencies:
6101 - readdirp "^4.0.1"
6102 -
5855 chownr@^1.0.1:
5856 version "1.1.4"
5857 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:
6120 resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
6121 integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
6122
6371 -commander@^4.0.0, commander@^4.0.1:
6123 +commander@^4.0.1:
6124 version "4.1.1"
6125 resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
6126 integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
@@ -6511,11 +6263,6 @@ connect-history-api-fallback@^2.0.0:
6263 resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8"
6264 integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==
6265
6514 -consola@^3.2.3:
6515 - version "3.4.0"
6516 - resolved "https://registry.yarnpkg.com/consola/-/consola-3.4.0.tgz#4cfc9348fd85ed16a17940b3032765e31061ab88"
6517 - integrity sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==
6518 -
6266 console-browserify@^1.1.0:
6267 version "1.2.0"
6268 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:
6786 dependencies:
6787 ms "2.1.2"
6788
7042 -debug@^4.3.7:
7043 - version "4.4.0"
7044 - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
7045 - integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
7046 - dependencies:
7047 - ms "^2.1.3"
7048 -
6789 decamelize@6.0.0:
6790 version "6.0.0"
6791 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:
7484 resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
7485 integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
7486
7747 -esbuild@^0.24.0:
7748 - version "0.24.2"
7749 - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.24.2.tgz#b5b55bee7de017bff5fb8a4e3e44f2ebe2c3567d"
7750 - integrity sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==
7751 - optionalDependencies:
7752 - "@esbuild/aix-ppc64" "0.24.2"
7753 - "@esbuild/android-arm" "0.24.2"
7754 - "@esbuild/android-arm64" "0.24.2"
7755 - "@esbuild/android-x64" "0.24.2"
7756 - "@esbuild/darwin-arm64" "0.24.2"
7757 - "@esbuild/darwin-x64" "0.24.2"
7758 - "@esbuild/freebsd-arm64" "0.24.2"
7759 - "@esbuild/freebsd-x64" "0.24.2"
7760 - "@esbuild/linux-arm" "0.24.2"
7761 - "@esbuild/linux-arm64" "0.24.2"
7762 - "@esbuild/linux-ia32" "0.24.2"
7763 - "@esbuild/linux-loong64" "0.24.2"
7764 - "@esbuild/linux-mips64el" "0.24.2"
7765 - "@esbuild/linux-ppc64" "0.24.2"
7766 - "@esbuild/linux-riscv64" "0.24.2"
7767 - "@esbuild/linux-s390x" "0.24.2"
7768 - "@esbuild/linux-x64" "0.24.2"
7769 - "@esbuild/netbsd-arm64" "0.24.2"
7770 - "@esbuild/netbsd-x64" "0.24.2"
7771 - "@esbuild/openbsd-arm64" "0.24.2"
7772 - "@esbuild/openbsd-x64" "0.24.2"
7773 - "@esbuild/sunos-x64" "0.24.2"
7774 - "@esbuild/win32-arm64" "0.24.2"
7775 - "@esbuild/win32-ia32" "0.24.2"
7776 - "@esbuild/win32-x64" "0.24.2"
7777 -
7487 escalade@^3.0.2:
7488 version "3.0.2"
7489 resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.0.2.tgz#6a580d70edb87880f22b4c91d0d56078df6962c4"
@@ -8649,11 +8358,6 @@ fd-slicer@~1.1.0:
8358 dependencies:
8359 pend "~1.2.0"
8360
8652 -fdir@^6.4.2:
8653 - version "6.4.3"
8654 - resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.3.tgz#011cdacf837eca9b811c89dbb902df714273db72"
8655 - integrity sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==
8656 -
8361 fetch-blob@^3.1.2, fetch-blob@^3.1.4:
8362 version "3.2.0"
8363 resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9"
@@ -9292,18 +8996,6 @@ glob@^10.2.5:
8996 minipass "^5.0.0 || ^6.0.2"
8997 path-scurry "^1.7.0"
8998
9295 -glob@^10.3.10:
9296 - version "10.4.5"
9297 - resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956"
9298 - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==
9299 - dependencies:
9300 - foreground-child "^3.1.0"
9301 - jackspeak "^3.1.2"
9302 - minimatch "^9.0.4"
9303 - minipass "^7.1.2"
9304 - package-json-from-dist "^1.0.0"
9305 - path-scurry "^1.11.1"
9306 -
8999 glob@^6.0.1:
9000 version "6.0.4"
9001 resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
@@ -11489,11 +11181,6 @@ jose@5.4.1:
11181 resolved "https://registry.yarnpkg.com/jose/-/jose-5.4.1.tgz#b471ee3963920ba5452fd1b1398c8ba72a7b2fcf"
11182 integrity sha512-U6QajmpV/nhL9SyfAewo000fkiRQ+Yd2H0lBxJJ9apjpOgkOcBQJWOrMo917lxLptdS/n/o/xPzMkXhF46K8hQ==
11183
11492 -joycon@^3.1.1:
11493 - version "3.1.1"
11494 - resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03"
11495 - integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==
11496 -
11184 jpeg-js@^0.4.2:
11185 version "0.4.4"
11186 resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa"
@@ -11880,11 +11567,6 @@ lighthouse-logger@^1.0.0:
11567 debug "^2.6.8"
11568 marky "^1.2.0"
11569
11883 -lilconfig@^3.1.1:
11884 - version "3.1.3"
11885 - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4"
11886 - integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==
11887 -
11570 lines-and-columns@^1.1.6:
11571 version "1.2.4"
11572 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:
11588 pinkie-promise "^2.0.0"
11589 strip-bom "^2.0.0"
11590
11909 -load-tsconfig@^0.2.3:
11910 - version "0.2.5"
11911 - resolved "https://registry.yarnpkg.com/load-tsconfig/-/load-tsconfig-0.2.5.tgz#453b8cd8961bfb912dea77eb6c168fe8cca3d3a1"
11912 - integrity sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==
11913 -
11591 loader-runner@^4.2.0:
11592 version "4.3.0"
11593 resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
@@ -12047,11 +11724,6 @@ lodash.omitby@4.6.0:
11724 resolved "https://registry.yarnpkg.com/lodash.omitby/-/lodash.omitby-4.6.0.tgz#5c15ff4754ad555016b53c041311e8f079204791"
11725 integrity sha1-XBX/R1StVVAWtTwEExHo8HkgR5E=
11726
12050 -lodash.sortby@^4.7.0:
12051 - version "4.7.0"
12052 - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
12053 - integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==
12054 -
11727 lodash.truncate@^4.4.2:
11728 version "4.4.2"
11729 resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
@@ -12572,7 +12244,7 @@ ms@2.1.2:
12244 resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
12245 integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
12246
12575 -ms@2.1.3, ms@^2.1.1, ms@^2.1.2, ms@^2.1.3:
12247 +ms@2.1.3, ms@^2.1.1, ms@^2.1.2:
12248 version "2.1.3"
12249 resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
12250 integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
@@ -12604,7 +12276,7 @@ mv@~2:
12276 ncp "~2.0.0"
12277 rimraf "~2.4.0"
12278
12607 -mz@2.7.0, mz@^2.7.0:
12279 +mz@2.7.0:
12280 version "2.7.0"
12281 resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
12282 integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
@@ -13646,11 +13318,6 @@ picocolors@^1.0.0:
13318 resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
13319 integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
13320
13649 -picocolors@^1.1.1:
13650 - version "1.1.1"
13651 - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
13652 - integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
13653 -
13321 picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1:
13322 version "2.3.1"
13323 resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
@@ -13821,13 +13488,6 @@ posix-character-classes@^0.1.0:
13488 resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
13489 integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
13490
13824 -postcss-load-config@^6.0.1:
13825 - version "6.0.1"
13826 - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz#6fd7dcd8ae89badcf1b2d644489cbabf83aa8096"
13827 - integrity sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==
13828 - dependencies:
13829 - lilconfig "^3.1.1"
13830 -
13491 postcss-modules-extract-imports@^1.2.0:
13492 version "1.2.1"
13493 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:
14216 micromatch "^3.1.10"
14217 readable-stream "^2.0.2"
14218
14559 -readdirp@^4.0.1:
14560 - version "4.1.2"
14561 - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d"
14562 - integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==
14563 -
14219 readdirp@~3.6.0:
14220 version "3.6.0"
14221 resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
@@ -15003,34 +14658,6 @@ rollup@^3.29.5:
14658 optionalDependencies:
14659 fsevents "~2.3.2"
14660
15006 -rollup@^4.24.0:
15007 - version "4.34.7"
15008 - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.34.7.tgz#e00d8550688a616a3481c6446bb688d4c753ba8f"
15009 - integrity sha512-8qhyN0oZ4x0H6wmBgfKxJtxM7qS98YJ0k0kNh5ECVtuchIJ7z9IVVvzpmtQyT10PXKMtBxYr1wQ5Apg8RS8kXQ==
15010 - dependencies:
15011 - "@types/estree" "1.0.6"
15012 - optionalDependencies:
15013 - "@rollup/rollup-android-arm-eabi" "4.34.7"
15014 - "@rollup/rollup-android-arm64" "4.34.7"
15015 - "@rollup/rollup-darwin-arm64" "4.34.7"
15016 - "@rollup/rollup-darwin-x64" "4.34.7"
15017 - "@rollup/rollup-freebsd-arm64" "4.34.7"
15018 - "@rollup/rollup-freebsd-x64" "4.34.7"
15019 - "@rollup/rollup-linux-arm-gnueabihf" "4.34.7"
15020 - "@rollup/rollup-linux-arm-musleabihf" "4.34.7"
15021 - "@rollup/rollup-linux-arm64-gnu" "4.34.7"
15022 - "@rollup/rollup-linux-arm64-musl" "4.34.7"
15023 - "@rollup/rollup-linux-loongarch64-gnu" "4.34.7"
15024 - "@rollup/rollup-linux-powerpc64le-gnu" "4.34.7"
15025 - "@rollup/rollup-linux-riscv64-gnu" "4.34.7"
15026 - "@rollup/rollup-linux-s390x-gnu" "4.34.7"
15027 - "@rollup/rollup-linux-x64-gnu" "4.34.7"
15028 - "@rollup/rollup-linux-x64-musl" "4.34.7"
15029 - "@rollup/rollup-win32-arm64-msvc" "4.34.7"
15030 - "@rollup/rollup-win32-ia32-msvc" "4.34.7"
15031 - "@rollup/rollup-win32-x64-msvc" "4.34.7"
15032 - fsevents "~2.3.2"
15033 -
14661 rrweb-cssom@^0.6.0:
14662 version "0.6.0"
14663 resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1"
@@ -15671,13 +15298,6 @@ source-map-url@^0.4.0:
15298 resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
15299 integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
15300
15674 -source-map@0.8.0-beta.0:
15675 - version "0.8.0-beta.0"
15676 - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11"
15677 - integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==
15678 - dependencies:
15679 - whatwg-url "^7.0.0"
15680 -
15301 source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.6:
15302 version "0.5.7"
15303 resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
@@ -16136,19 +15756,6 @@ style-loader@^1.2.1:
15756 loader-utils "^2.0.0"
15757 schema-utils "^2.6.6"
15758
16139 -sucrase@^3.35.0:
16140 - version "3.35.0"
16141 - resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263"
16142 - integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==
16143 - dependencies:
16144 - "@jridgewell/gen-mapping" "^0.3.2"
16145 - commander "^4.0.0"
16146 - glob "^10.3.10"
16147 - lines-and-columns "^1.1.6"
16148 - mz "^2.7.0"
16149 - pirates "^4.0.1"
16150 - ts-interface-checker "^0.1.9"
16151 -
15759 sumchecker@^3.0.1:
15760 version "3.0.1"
15761 resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42"
@@ -16437,19 +16044,6 @@ tiny-warning@^1.0.3:
16044 resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
16045 integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
16046
16440 -tinyexec@^0.3.1:
16441 - version "0.3.2"
16442 - resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2"
16443 - integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==
16444 -
16445 -tinyglobby@^0.2.9:
16446 - version "0.2.10"
16447 - resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.10.tgz#e712cf2dc9b95a1f5c5bbd159720e15833977a0f"
16448 - integrity sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==
16449 - dependencies:
16450 - fdir "^6.4.2"
16451 - picomatch "^4.0.2"
16452 -
16047 titleize@^3.0.0:
16048 version "3.0.0"
16049 resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53"
@@ -16556,13 +16150,6 @@ tough-cookie@^4.1.2:
16150 universalify "^0.2.0"
16151 url-parse "^1.5.3"
16152
16559 -tr46@^1.0.1:
16560 - version "1.0.1"
16561 - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
16562 - integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==
16563 - dependencies:
16564 - punycode "^2.1.0"
16565 -
16153 tr46@^4.1.1:
16154 version "4.1.1"
16155 resolved "https://registry.yarnpkg.com/tr46/-/tr46-4.1.1.tgz#281a758dcc82aeb4fe38c7dfe4d11a395aac8469"
@@ -16580,11 +16167,6 @@ traverse-chain@~0.1.0:
16167 resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1"
16168 integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=
16169
16583 -tree-kill@^1.2.2:
16584 - version "1.2.2"
16585 - resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
16586 - integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
16587 -
16170 trim-newlines@^1.0.0:
16171 version "1.0.0"
16172 resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
@@ -16602,11 +16184,6 @@ ts-api-utils@^1.0.1:
16184 resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1"
16185 integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==
16186
16605 -ts-interface-checker@^0.1.9:
16606 - version "0.1.13"
16607 - resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
16608 - integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
16609 -
16187 ts-node@8.9.1:
16188 version "8.9.1"
16189 resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.9.1.tgz#2f857f46c47e91dcd28a14e052482eb14cfd65a5"
@@ -16633,28 +16210,6 @@ tslib@^2.3.0:
16210 resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
16211 integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
16212
16636 -tsup@^8.3.5:
16637 - version "8.3.6"
16638 - resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.3.6.tgz#a10eb2dc27f84b510a0f00341ab75cad03d13a88"
16639 - integrity sha512-XkVtlDV/58S9Ye0JxUUTcrQk4S+EqlOHKzg6Roa62rdjL1nGWNUstG0xgI4vanHdfIpjP448J8vlN0oK6XOJ5g==
16640 - dependencies:
16641 - bundle-require "^5.0.0"
16642 - cac "^6.7.14"
16643 - chokidar "^4.0.1"
16644 - consola "^3.2.3"
16645 - debug "^4.3.7"
16646 - esbuild "^0.24.0"
16647 - joycon "^3.1.1"
16648 - picocolors "^1.1.1"
16649 - postcss-load-config "^6.0.1"
16650 - resolve-from "^5.0.0"
16651 - rollup "^4.24.0"
16652 - source-map "0.8.0-beta.0"
16653 - sucrase "^3.35.0"
16654 - tinyexec "^0.3.1"
16655 - tinyglobby "^0.2.9"
16656 - tree-kill "^1.2.2"
16657 -
16213 tsutils@^3.17.1:
16214 version "3.17.1"
16215 resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
@@ -17287,11 +16842,6 @@ webidl-conversions@^3.0.0:
16842 resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
16843 integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
16844
17290 -webidl-conversions@^4.0.2:
17291 - version "4.0.2"
17292 - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
17293 - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
17294 -
16845 webidl-conversions@^7.0.0:
16846 version "7.0.0"
16847 resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a"
@@ -17462,15 +17012,6 @@ whatwg-url@^5.0.0:
17012 tr46 "~0.0.3"
17013 webidl-conversions "^3.0.0"
17014
17465 -whatwg-url@^7.0.0:
17466 - version "7.1.0"
17467 - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"
17468 - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==
17469 - dependencies:
17470 - lodash.sortby "^4.7.0"
17471 - tr46 "^1.0.1"
17472 - webidl-conversions "^4.0.2"
17473 -
17015 when@3.7.7:
17016 version "3.7.7"
17017 resolved "https://registry.yarnpkg.com/when/-/when-3.7.7.tgz#aba03fc3bb736d6c88b091d013d8a8e590d84718"