11import * 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" ;
33import type { Scope } from "@typescript-eslint/scope-manager" ;
4- import { DefinitionType } from "@typescript-eslint/scope-manager" ;
54import type { TSESTree } from "@typescript-eslint/types" ;
65import { AST_NODE_TYPES } from "@typescript-eslint/types" ;
76import { match } from "ts-pattern" ;
87
8+ import { getVariableNode } from "./get-variable-node" ;
9+
910export type Construction = Data . TaggedEnum < {
1011 Array : {
1112 node : TSESTree . ArrayExpression ;
@@ -47,7 +48,10 @@ export type Construction = Data.TaggedEnum<{
4748 node : TSESTree . NewExpression ;
4849 usage : O . Option < TSESTree . Node > ;
4950 } ;
50- None : { } ;
51+ None : {
52+ node : TSESTree . Node ;
53+ usage : O . Option < TSESTree . Node > ;
54+ } ;
5155 ObjectExpression : {
5256 node : TSESTree . ObjectExpression ;
5357 usage : O . Option < TSESTree . Node > ;
@@ -95,7 +99,7 @@ export function inspectConstruction(
9599 if ( hint & ConstructionHint . StrictCallExpression ) {
96100 return Construction . CallExpression ( { node, usage : O . none ( ) } ) ;
97101 }
98- return Construction . None ( ) ;
102+ return Construction . None ( { node , usage : O . none ( ) } ) ;
99103 } )
100104 . when ( AST . is ( AST_NODE_TYPES . NewExpression ) , ( node ) => Construction . NewExpression ( { node, usage : O . none ( ) } ) )
101105 . when (
@@ -108,7 +112,7 @@ export function inspectConstruction(
108112 } ,
109113 )
110114 . 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 ( ) } ) ;
112116 const object = detect ( node . object ) ;
113117 if ( object . _tag === "None" ) return object ;
114118 return {
@@ -117,7 +121,7 @@ export function inspectConstruction(
117121 } as const satisfies Construction ;
118122 } )
119123 . 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 ( ) } ) ;
121125 const right = detect ( node . right ) ;
122126 if ( right . _tag === "None" ) return right ;
123127 return Construction . AssignmentExpression ( {
@@ -126,7 +130,7 @@ export function inspectConstruction(
126130 } ) ;
127131 } )
128132 . 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 ( ) } ) ;
130134 const right = detect ( node . right ) ;
131135 if ( right . _tag === "None" ) return right ;
132136 return Construction . AssignmentPattern ( {
@@ -135,54 +139,46 @@ export function inspectConstruction(
135139 } ) ;
136140 } )
137141 . 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 ( ) } ) ;
139143 const left = detect ( node . left ) ;
140144 if ( left . _tag !== "None" ) return left ;
141145 return detect ( node . right ) ;
142146 } )
143147 . when ( AST . is ( AST_NODE_TYPES . ConditionalExpression ) , ( node ) => {
144148 if ( ! ( "consequent" in node && "alternate" in node && ! isNullable ( node . alternate ) ) ) {
145- return Construction . None ( ) ;
149+ return Construction . None ( { node , usage : O . none ( ) } ) ;
146150 }
147151 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 ( ) } ) ;
149153 return detect ( node . alternate ) ;
150154 } )
151155 . 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 ;
172168 } )
173169 . when ( AST . is ( AST_NODE_TYPES . Literal ) , ( node ) => {
174170 if ( "regex" in node ) {
175171 return Construction . RegExpLiteral ( { node, usage : O . none ( ) } ) ;
176172 }
177- return Construction . None ( ) ;
173+ return Construction . None ( { node , usage : O . none ( ) } ) ;
178174 } )
179175 . when ( AST . isTypeExpression , ( ) => {
180176 if ( ! ( "expression" in node ) || ! isObject ( node . expression ) ) {
181- return Construction . None ( ) ;
177+ return Construction . None ( { node , usage : O . none ( ) } ) ;
182178 }
183179 return detect ( node . expression ) ;
184180 } )
185- . otherwise ( ( ) => Construction . None ( ) ) ;
181+ . otherwise ( ( ) => Construction . None ( { node , usage : O . none ( ) } ) ) ;
186182 } ;
187183 return detect ( node ) ;
188184}
0 commit comments