|
1 | | -import * as AST from "@eslint-react/ast"; |
2 | | -import { identity } from "@eslint-react/eff"; |
3 | | -import { findVariable } from "@eslint-react/var"; |
4 | 1 | import type { Scope } from "@typescript-eslint/scope-manager"; |
5 | | -import type { TSESTree } from "@typescript-eslint/types"; |
6 | | -import { AST_NODE_TYPES as T } from "@typescript-eslint/types"; |
7 | | -import { P, match } from "ts-pattern"; |
8 | 2 |
|
9 | | -/** |
10 | | - * Get the arguments of a require expression |
11 | | - * @param node The node to match |
12 | | - * @returns The require expression arguments or undefined if the node is not a require expression |
13 | | - */ |
14 | | -function getRequireExpressionArguments(node: TSESTree.Node) { |
15 | | - return match<typeof node, TSESTree.CallExpressionArgument[] | null>(node) |
16 | | - // require("source") |
17 | | - .with({ type: T.CallExpression, arguments: P.select(), callee: { type: T.Identifier, name: "require" } }, identity) |
18 | | - // require("source").variable |
19 | | - .with({ type: T.MemberExpression, object: P.select() }, getRequireExpressionArguments) |
20 | | - .otherwise(() => null); |
21 | | -} |
| 3 | +import { isInitializedFromSource } from "./is-from-source"; |
22 | 4 |
|
23 | 5 | /** |
24 | 6 | * Check if an identifier name is initialized from react |
25 | 7 | * @param name The top-level identifier's name |
26 | 8 | * @param importSource The import source to check against |
27 | 9 | * @param initialScope Initial scope to search for the identifier |
28 | 10 | * @returns Whether the identifier name is initialized from react |
29 | | - * @internal |
30 | 11 | */ |
31 | 12 | export function isInitializedFromReact( |
32 | 13 | name: string, |
33 | 14 | importSource: string, |
34 | 15 | initialScope: Scope, |
35 | | -): boolean { |
36 | | - if (name.toLowerCase() === "react") return true; |
37 | | - const latestDef = findVariable(name, initialScope)?.defs.at(-1); |
38 | | - if (latestDef == null) return false; |
39 | | - const { node, parent } = latestDef; |
40 | | - if (node.type === T.VariableDeclarator && node.init != null) { |
41 | | - const { init } = node; |
42 | | - // check for: `variable = React.variable` |
43 | | - if (init.type === T.MemberExpression && init.object.type === T.Identifier) { |
44 | | - return isInitializedFromReact(init.object.name, importSource, initialScope); |
45 | | - } |
46 | | - // check for: `{ variable } = React` |
47 | | - if (init.type === T.Identifier) { |
48 | | - return isInitializedFromReact(init.name, importSource, initialScope); |
49 | | - } |
50 | | - // check for: `variable = require('react')` or `variable = require('react').variable` |
51 | | - const args = getRequireExpressionArguments(init); |
52 | | - const arg0 = args?.[0]; |
53 | | - if (arg0 == null || !AST.isLiteral(arg0, "string")) { |
54 | | - return false; |
55 | | - } |
56 | | - // check for: `require('react')` or `require('react/...')` |
57 | | - return arg0.value === importSource || arg0.value.startsWith(`${importSource}/`); |
58 | | - } |
59 | | - // latest definition is an import declaration: import { variable } from 'react' |
60 | | - return parent?.type === T.ImportDeclaration && parent.source.value === importSource; |
| 16 | +) { |
| 17 | + return name.toLowerCase() === "react" || isInitializedFromSource(name, importSource, initialScope); |
61 | 18 | } |
0 commit comments