1
1
import * as AST from "@eslint-react/ast" ;
2
- import { Data , isNullable , isObject , isString , O } from "@eslint-react/eff" ;
2
+ import { Data , F , isNullable , isObject , isString , not , O } from "@eslint-react/eff" ;
3
3
import type { Scope } from "@typescript-eslint/scope-manager" ;
4
- import { DefinitionType } from "@typescript-eslint/scope-manager" ;
5
4
import type { TSESTree } from "@typescript-eslint/types" ;
6
5
import { AST_NODE_TYPES } from "@typescript-eslint/types" ;
7
6
import { match } from "ts-pattern" ;
8
7
8
+ import { getVariableNode } from "./get-variable-node" ;
9
+
9
10
export type Construction = Data . TaggedEnum < {
10
11
Array : {
11
12
node : TSESTree . ArrayExpression ;
@@ -47,7 +48,10 @@ export type Construction = Data.TaggedEnum<{
47
48
node : TSESTree . NewExpression ;
48
49
usage : O . Option < TSESTree . Node > ;
49
50
} ;
50
- None : { } ;
51
+ None : {
52
+ node : TSESTree . Node ;
53
+ usage : O . Option < TSESTree . Node > ;
54
+ } ;
51
55
ObjectExpression : {
52
56
node : TSESTree . ObjectExpression ;
53
57
usage : O . Option < TSESTree . Node > ;
@@ -95,7 +99,7 @@ export function inspectConstruction(
95
99
if ( hint & ConstructionHint . StrictCallExpression ) {
96
100
return Construction . CallExpression ( { node, usage : O . none ( ) } ) ;
97
101
}
98
- return Construction . None ( ) ;
102
+ return Construction . None ( { node , usage : O . none ( ) } ) ;
99
103
} )
100
104
. when ( AST . is ( AST_NODE_TYPES . NewExpression ) , ( node ) => Construction . NewExpression ( { node, usage : O . none ( ) } ) )
101
105
. when (
@@ -108,7 +112,7 @@ export function inspectConstruction(
108
112
} ,
109
113
)
110
114
. when ( AST . is ( AST_NODE_TYPES . MemberExpression ) , ( node ) => {
111
- if ( ! ( "object" in node ) ) return Construction . None ( ) ;
115
+ if ( ! ( "object" in node ) ) return Construction . None ( { node , usage : O . none ( ) } ) ;
112
116
const object = detect ( node . object ) ;
113
117
if ( object . _tag === "None" ) return object ;
114
118
return {
@@ -117,7 +121,7 @@ export function inspectConstruction(
117
121
} as const satisfies Construction ;
118
122
} )
119
123
. when ( AST . is ( AST_NODE_TYPES . AssignmentExpression ) , ( node ) => {
120
- if ( ! ( "right" in node ) ) return Construction . None ( ) ;
124
+ if ( ! ( "right" in node ) ) return Construction . None ( { node , usage : O . none ( ) } ) ;
121
125
const right = detect ( node . right ) ;
122
126
if ( right . _tag === "None" ) return right ;
123
127
return Construction . AssignmentExpression ( {
@@ -126,7 +130,7 @@ export function inspectConstruction(
126
130
} ) ;
127
131
} )
128
132
. when ( AST . is ( AST_NODE_TYPES . AssignmentPattern ) , ( node ) => {
129
- if ( ! ( "right" in node ) ) return Construction . None ( ) ;
133
+ if ( ! ( "right" in node ) ) return Construction . None ( { node , usage : O . none ( ) } ) ;
130
134
const right = detect ( node . right ) ;
131
135
if ( right . _tag === "None" ) return right ;
132
136
return Construction . AssignmentPattern ( {
@@ -135,54 +139,46 @@ export function inspectConstruction(
135
139
} ) ;
136
140
} )
137
141
. when ( AST . is ( AST_NODE_TYPES . LogicalExpression ) , ( node ) => {
138
- if ( ! ( "left" in node && "right" in node ) ) return Construction . None ( ) ;
142
+ if ( ! ( "left" in node && "right" in node ) ) return Construction . None ( { node , usage : O . none ( ) } ) ;
139
143
const left = detect ( node . left ) ;
140
144
if ( left . _tag !== "None" ) return left ;
141
145
return detect ( node . right ) ;
142
146
} )
143
147
. when ( AST . is ( AST_NODE_TYPES . ConditionalExpression ) , ( node ) => {
144
148
if ( ! ( "consequent" in node && "alternate" in node && ! isNullable ( node . alternate ) ) ) {
145
- return Construction . None ( ) ;
149
+ return Construction . None ( { node , usage : O . none ( ) } ) ;
146
150
}
147
151
const consequent = detect ( node . consequent ) ;
148
- if ( consequent . _tag !== "None" ) return Construction . None ( ) ;
152
+ if ( consequent . _tag !== "None" ) return Construction . None ( { node , usage : O . none ( ) } ) ;
149
153
return detect ( node . alternate ) ;
150
154
} )
151
155
. when ( AST . is ( AST_NODE_TYPES . Identifier ) , ( node ) => {
152
- if ( ! ( "name" in node && isString ( node . name ) ) ) return Construction . None ( ) ;
153
- const maybeLatestDef = O . fromNullable ( initialScope . set . get ( node . name ) ?. defs . at ( - 1 ) ) ;
154
- if ( O . isNone ( maybeLatestDef ) ) return Construction . None ( ) ;
155
- const latestDef = maybeLatestDef . value ;
156
- if (
157
- latestDef . type !== DefinitionType . Variable
158
- && latestDef . type !== DefinitionType . FunctionName
159
- ) {
160
- return Construction . None ( ) ;
161
- }
162
- if ( latestDef . node . type === AST_NODE_TYPES . FunctionDeclaration ) {
163
- return Construction . FunctionDeclaration ( {
164
- node : latestDef . node ,
165
- usage : O . some ( node ) ,
166
- } ) ;
167
- }
168
- if ( ! ( "init" in latestDef . node ) || latestDef . node . init === null ) {
169
- return Construction . None ( ) ;
170
- }
171
- return detect ( latestDef . node . init ) ;
156
+ if ( ! ( "name" in node && isString ( node . name ) ) ) return Construction . None ( { node, usage : O . none ( ) } ) ;
157
+ const construction = F . pipe (
158
+ O . fromNullable ( initialScope . set . get ( node . name ) ) ,
159
+ O . flatMap ( getVariableNode ( - 1 ) ) ,
160
+ O . map ( detect ) ,
161
+ O . filter ( not ( Construction . $is ( "None" ) ) ) ,
162
+ ) ;
163
+ if ( O . isNone ( construction ) ) return Construction . None ( { node, usage : O . none ( ) } ) ;
164
+ return {
165
+ ...construction . value ,
166
+ usage : O . some ( node ) ,
167
+ } as const ;
172
168
} )
173
169
. when ( AST . is ( AST_NODE_TYPES . Literal ) , ( node ) => {
174
170
if ( "regex" in node ) {
175
171
return Construction . RegExpLiteral ( { node, usage : O . none ( ) } ) ;
176
172
}
177
- return Construction . None ( ) ;
173
+ return Construction . None ( { node , usage : O . none ( ) } ) ;
178
174
} )
179
175
. when ( AST . isTypeExpression , ( ) => {
180
176
if ( ! ( "expression" in node ) || ! isObject ( node . expression ) ) {
181
- return Construction . None ( ) ;
177
+ return Construction . None ( { node , usage : O . none ( ) } ) ;
182
178
}
183
179
return detect ( node . expression ) ;
184
180
} )
185
- . otherwise ( ( ) => Construction . None ( ) ) ;
181
+ . otherwise ( ( ) => Construction . None ( { node , usage : O . none ( ) } ) ) ;
186
182
} ;
187
183
return detect ( node ) ;
188
184
}
0 commit comments