@pikku/inspector 0.6.4 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/add-channel.d.ts +12 -2
- package/dist/add-channel.js +336 -109
- package/dist/add-functions.d.ts +7 -0
- package/dist/add-functions.js +269 -0
- package/dist/add-http-route.d.ts +15 -3
- package/dist/add-http-route.js +69 -80
- package/dist/add-schedule.d.ts +1 -1
- package/dist/add-schedule.js +14 -4
- package/dist/inspector.js +14 -4
- package/dist/types.d.ts +7 -10
- package/dist/utils.d.ts +21 -27
- package/dist/utils.js +631 -211
- package/dist/visit.d.ts +2 -1
- package/dist/visit.js +9 -4
- package/package.json +2 -2
- package/src/add-channel.ts +442 -140
- package/src/add-functions.ts +376 -0
- package/src/add-http-route.ts +94 -109
- package/src/add-schedule.ts +24 -4
- package/src/inspector.ts +17 -5
- package/src/types.ts +8 -12
- package/src/utils.ts +778 -286
- package/src/visit.ts +16 -6
- package/tsconfig.tsbuildinfo +1 -1
package/src/utils.ts
CHANGED
|
@@ -1,356 +1,848 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
|
-
import { TypesMap } from './types-map.js'
|
|
3
2
|
import { InspectorFilters } from './types.js'
|
|
4
3
|
|
|
5
|
-
type
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
type ExtractedFunctionName = {
|
|
5
|
+
pikkuFuncName: string
|
|
6
|
+
name: string
|
|
7
|
+
exportedName: string | null
|
|
8
|
+
functionName: string | null
|
|
9
|
+
propertyName: string | null
|
|
11
10
|
}
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Generate a deterministic "anonymous" name for any expression node,
|
|
14
|
+
* but if it's an Identifier pointing to a function, resolve it back
|
|
15
|
+
* to the function's declaration (so you get the true source location).
|
|
16
|
+
*/
|
|
17
|
+
export function makeDeterministicAnonName(
|
|
18
|
+
start: ts.Node,
|
|
19
|
+
checker: ts.TypeChecker
|
|
20
|
+
): string {
|
|
21
|
+
let node: ts.Node = start
|
|
22
|
+
let target: ts.Node = start
|
|
23
|
+
|
|
24
|
+
// Handle the case where we're starting with an identifier directly
|
|
25
|
+
if (ts.isIdentifier(node)) {
|
|
26
|
+
const sym = checker.getSymbolAtLocation(node)
|
|
27
|
+
if (sym) {
|
|
28
|
+
let resolvedSym = sym
|
|
29
|
+
if (resolvedSym.flags & ts.SymbolFlags.Alias) {
|
|
30
|
+
resolvedSym = checker.getAliasedSymbol(resolvedSym) ?? resolvedSym
|
|
31
|
+
}
|
|
16
32
|
|
|
17
|
-
|
|
33
|
+
const decls = resolvedSym.declarations ?? []
|
|
34
|
+
if (decls.length > 0) {
|
|
35
|
+
// Start with the declaration, not the reference
|
|
36
|
+
const decl = decls[0]!
|
|
37
|
+
|
|
38
|
+
// If it's a variable declaration with a function initializer, use the function directly
|
|
39
|
+
if (
|
|
40
|
+
ts.isVariableDeclaration(decl) &&
|
|
41
|
+
decl.initializer &&
|
|
42
|
+
(ts.isFunctionExpression(decl.initializer) ||
|
|
43
|
+
ts.isArrowFunction(decl.initializer))
|
|
44
|
+
) {
|
|
45
|
+
target = decl.initializer
|
|
46
|
+
// Return early - we found the function directly
|
|
47
|
+
const sf = target.getSourceFile()
|
|
48
|
+
const file = sf.fileName.replace(/[^A-Za-z0-9_]/g, '_')
|
|
49
|
+
const { line, character } = ts.getLineAndCharacterOfPosition(
|
|
50
|
+
sf,
|
|
51
|
+
target.getStart()
|
|
52
|
+
)
|
|
53
|
+
return `pikkuFn_${file}_L${line + 1}C${character + 1}`
|
|
54
|
+
}
|
|
55
|
+
// Otherwise continue resolution with the declaration
|
|
56
|
+
node = decl
|
|
57
|
+
target = decl!
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// In an object literal property value, first try to resolve the identifier
|
|
18
63
|
if (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
type === 'any'
|
|
64
|
+
ts.isPropertyAssignment(node.parent) &&
|
|
65
|
+
node === node.parent.initializer &&
|
|
66
|
+
ts.isIdentifier(node)
|
|
23
67
|
) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
68
|
+
const sym = checker.getSymbolAtLocation(node)
|
|
69
|
+
if (sym) {
|
|
70
|
+
// Process the symbol to find the real declaration
|
|
71
|
+
let resolvedSym = sym
|
|
72
|
+
if (resolvedSym.flags & ts.SymbolFlags.Alias) {
|
|
73
|
+
resolvedSym = checker.getAliasedSymbol(resolvedSym) ?? resolvedSym
|
|
74
|
+
}
|
|
28
75
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
76
|
+
const decls = resolvedSym.declarations ?? []
|
|
77
|
+
if (decls.length > 0) {
|
|
78
|
+
// Found a declaration - use it as our new target
|
|
79
|
+
const decl = decls[0]
|
|
33
80
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
81
|
+
if (!decl) {
|
|
82
|
+
throw new Error('No declaration found')
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// If it's a variable declaration with an initializer function, use that
|
|
86
|
+
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
87
|
+
if (
|
|
88
|
+
ts.isFunctionExpression(decl.initializer) ||
|
|
89
|
+
ts.isArrowFunction(decl.initializer)
|
|
90
|
+
) {
|
|
91
|
+
target = decl.initializer
|
|
92
|
+
// Return early - we found the function directly
|
|
93
|
+
const sf = target.getSourceFile()
|
|
94
|
+
const file = sf.fileName.replace(/[^A-Za-z0-9_]/g, '_')
|
|
95
|
+
const { line, character } = ts.getLineAndCharacterOfPosition(
|
|
96
|
+
sf,
|
|
97
|
+
target.getStart()
|
|
98
|
+
)
|
|
99
|
+
return `pikkuFn_${file}_L${line + 1}C${character + 1}`
|
|
100
|
+
}
|
|
101
|
+
} else if (ts.isFunctionDeclaration(decl)) {
|
|
102
|
+
// Already a function declaration
|
|
103
|
+
target = decl
|
|
104
|
+
// Return early
|
|
105
|
+
const sf = target.getSourceFile()
|
|
106
|
+
const file = sf.fileName.replace(/[^A-Za-z0-9_]/g, '_')
|
|
107
|
+
const { line, character } = ts.getLineAndCharacterOfPosition(
|
|
108
|
+
sf,
|
|
109
|
+
target.getStart()
|
|
110
|
+
)
|
|
111
|
+
return `pikkuFn_${file}_L${line + 1}C${character + 1}`
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// If we didn't return early, continue with this declaration
|
|
115
|
+
node = decl
|
|
116
|
+
target = decl
|
|
117
|
+
}
|
|
118
|
+
}
|
|
47
119
|
}
|
|
48
120
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
121
|
+
const seen = new Set<ts.Node>()
|
|
122
|
+
for (let depth = 0; depth < 10; depth++) {
|
|
123
|
+
if (!ts.isIdentifier(node) || seen.has(node)) break
|
|
124
|
+
seen.add(node)
|
|
125
|
+
|
|
126
|
+
let sym = checker.getSymbolAtLocation(node)
|
|
127
|
+
if (!sym) break
|
|
128
|
+
if (sym.flags & ts.SymbolFlags.Alias) {
|
|
129
|
+
sym = checker.getAliasedSymbol(sym) ?? sym
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const allDecls = sym.declarations ?? []
|
|
133
|
+
// prefer real .ts/.tsx implementation files
|
|
134
|
+
const implDecls = allDecls.filter(
|
|
135
|
+
(d) => !d.getSourceFile().isDeclarationFile
|
|
136
|
+
)
|
|
137
|
+
const decls = implDecls.length ? implDecls : allDecls
|
|
138
|
+
|
|
139
|
+
let didResolve = false
|
|
140
|
+
for (const decl of decls) {
|
|
141
|
+
// 1) direct function foo() {} or function-expression
|
|
142
|
+
if (
|
|
143
|
+
ts.isFunctionDeclaration(decl) ||
|
|
144
|
+
ts.isFunctionExpression(decl) ||
|
|
145
|
+
ts.isArrowFunction(decl)
|
|
146
|
+
) {
|
|
147
|
+
target = decl
|
|
148
|
+
didResolve = true
|
|
149
|
+
break
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 2) const foo = () => {} or foo = function() {}
|
|
153
|
+
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
154
|
+
const init = decl.initializer
|
|
155
|
+
if (ts.isFunctionExpression(init) || ts.isArrowFunction(init)) {
|
|
156
|
+
target = init
|
|
157
|
+
didResolve = true
|
|
158
|
+
break
|
|
68
159
|
}
|
|
69
|
-
|
|
70
|
-
|
|
160
|
+
// 2b) const foo = bar; (follow the next identifier)
|
|
161
|
+
if (ts.isIdentifier(init)) {
|
|
162
|
+
node = init
|
|
163
|
+
target = init
|
|
164
|
+
didResolve = true
|
|
165
|
+
break
|
|
71
166
|
}
|
|
72
|
-
|
|
73
|
-
})
|
|
74
|
-
.flat()
|
|
75
|
-
result.names = new Set(uniqueNames)
|
|
76
|
-
result.types = types
|
|
77
|
-
}
|
|
167
|
+
}
|
|
78
168
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
169
|
+
// 3) Handle shorthand property assignments: { foo } (equivalent to { foo: foo })
|
|
170
|
+
if (ts.isShorthandPropertyAssignment(decl)) {
|
|
171
|
+
// Get the symbol for the shorthand property
|
|
172
|
+
const shorthandSym = checker.getShorthandAssignmentValueSymbol(decl)
|
|
173
|
+
if (
|
|
174
|
+
shorthandSym &&
|
|
175
|
+
shorthandSym.declarations &&
|
|
176
|
+
shorthandSym.declarations.length > 0
|
|
177
|
+
) {
|
|
178
|
+
// Use the first declaration as our new target
|
|
179
|
+
const shorthandDecl = shorthandSym.declarations[0]!
|
|
180
|
+
target = shorthandDecl
|
|
84
181
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
ts.TypeFlags.String |
|
|
89
|
-
ts.TypeFlags.Boolean |
|
|
90
|
-
ts.TypeFlags.BigInt |
|
|
91
|
-
ts.TypeFlags.ESSymbol |
|
|
92
|
-
ts.TypeFlags.Void |
|
|
93
|
-
ts.TypeFlags.Undefined |
|
|
94
|
-
ts.TypeFlags.Null |
|
|
95
|
-
ts.TypeFlags.Any |
|
|
96
|
-
ts.TypeFlags.Unknown
|
|
97
|
-
|
|
98
|
-
return (type.flags & primitiveFlags) !== 0
|
|
99
|
-
}
|
|
182
|
+
if (!shorthandDecl) {
|
|
183
|
+
throw new Error('No shorthand declaration found')
|
|
184
|
+
}
|
|
100
185
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
186
|
+
// Check the type of declaration and extract the appropriate identifier to continue resolving
|
|
187
|
+
if (
|
|
188
|
+
ts.isVariableDeclaration(shorthandDecl) &&
|
|
189
|
+
ts.isIdentifier(shorthandDecl.name)
|
|
190
|
+
) {
|
|
191
|
+
node = shorthandDecl.name
|
|
192
|
+
didResolve = true
|
|
193
|
+
break
|
|
194
|
+
} else if (
|
|
195
|
+
ts.isFunctionDeclaration(shorthandDecl) &&
|
|
196
|
+
shorthandDecl.name &&
|
|
197
|
+
ts.isIdentifier(shorthandDecl.name)
|
|
198
|
+
) {
|
|
199
|
+
node = shorthandDecl.name
|
|
200
|
+
didResolve = true
|
|
201
|
+
break
|
|
202
|
+
} else if (
|
|
203
|
+
ts.isParameter(shorthandDecl) &&
|
|
204
|
+
ts.isIdentifier(shorthandDecl.name)
|
|
205
|
+
) {
|
|
206
|
+
node = shorthandDecl.name
|
|
207
|
+
didResolve = true
|
|
208
|
+
break
|
|
209
|
+
} else if (
|
|
210
|
+
ts.isPropertyDeclaration(shorthandDecl) &&
|
|
211
|
+
ts.isIdentifier(shorthandDecl.name)
|
|
212
|
+
) {
|
|
213
|
+
node = shorthandDecl.name
|
|
214
|
+
didResolve = true
|
|
215
|
+
break
|
|
216
|
+
} else if (
|
|
217
|
+
ts.isMethodDeclaration(shorthandDecl) &&
|
|
218
|
+
ts.isIdentifier(shorthandDecl.name)
|
|
219
|
+
) {
|
|
220
|
+
node = shorthandDecl.name
|
|
221
|
+
didResolve = true
|
|
222
|
+
break
|
|
223
|
+
}
|
|
224
|
+
}
|
|
115
225
|
}
|
|
226
|
+
|
|
227
|
+
// 4) Handle method declarations in classes/objects
|
|
228
|
+
if (ts.isMethodDeclaration(decl)) {
|
|
229
|
+
target = decl
|
|
230
|
+
didResolve = true
|
|
231
|
+
break
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// you can add more cases here if your setup uses imports, etc.
|
|
116
235
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (name) {
|
|
120
|
-
types.push(type)
|
|
121
|
-
names.push(name)
|
|
122
|
-
}
|
|
236
|
+
|
|
237
|
+
if (!didResolve) break
|
|
123
238
|
}
|
|
124
239
|
|
|
125
|
-
|
|
240
|
+
const sf = target.getSourceFile()
|
|
241
|
+
const file = sf.fileName.replace(/[^A-Za-z0-9_]/g, '_')
|
|
242
|
+
const { line, character } = ts.getLineAndCharacterOfPosition(
|
|
243
|
+
sf,
|
|
244
|
+
target.getStart()
|
|
245
|
+
)
|
|
246
|
+
return `pikkuFn_${file}_L${line + 1}C${character + 1}`
|
|
126
247
|
}
|
|
127
248
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
249
|
+
/**
|
|
250
|
+
* Updated function to extract and prioritize function names correctly
|
|
251
|
+
* This function follows the priority:
|
|
252
|
+
* 1. Object with a name property
|
|
253
|
+
* 2. Exported name
|
|
254
|
+
* 3. Fallback to deterministic name
|
|
255
|
+
*/
|
|
256
|
+
export function extractFunctionName(
|
|
257
|
+
callExpr: ts.Node,
|
|
258
|
+
checker: ts.TypeChecker
|
|
259
|
+
): ExtractedFunctionName {
|
|
260
|
+
const parent: any = callExpr.parent
|
|
261
|
+
|
|
262
|
+
// Initialize the result
|
|
263
|
+
const result: ExtractedFunctionName = {
|
|
264
|
+
pikkuFuncName: '', // Will be populated later
|
|
265
|
+
name: '', // This will hold our "best" name based on priority
|
|
266
|
+
exportedName: null,
|
|
267
|
+
functionName: null,
|
|
268
|
+
propertyName: null,
|
|
269
|
+
}
|
|
137
270
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
271
|
+
// Special case for addHTTPRoute: if this is an identifier within an object literal,
|
|
272
|
+
// it might be coming from the HTTP route handling flow
|
|
273
|
+
if (
|
|
274
|
+
ts.isIdentifier(callExpr) &&
|
|
275
|
+
callExpr.parent &&
|
|
276
|
+
ts.isPropertyAssignment(callExpr.parent)
|
|
277
|
+
) {
|
|
278
|
+
// Try to handle the special case for HTTP route functions
|
|
279
|
+
const sym = checker.getSymbolAtLocation(callExpr)
|
|
280
|
+
if (sym) {
|
|
281
|
+
let resolvedSym = sym
|
|
282
|
+
if (resolvedSym.flags & ts.SymbolFlags.Alias) {
|
|
283
|
+
resolvedSym = checker.getAliasedSymbol(resolvedSym) ?? resolvedSym
|
|
284
|
+
}
|
|
144
285
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
286
|
+
const decls = resolvedSym.declarations ?? []
|
|
287
|
+
if (decls.length > 0) {
|
|
288
|
+
const decl = decls[0]!
|
|
289
|
+
// Check if the declaration is a variable that uses pikkuSessionlessFunc
|
|
290
|
+
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
291
|
+
if (
|
|
292
|
+
ts.isCallExpression(decl.initializer) &&
|
|
293
|
+
ts.isIdentifier(decl.initializer.expression) &&
|
|
294
|
+
decl.initializer.expression.text.startsWith('pikku')
|
|
295
|
+
) {
|
|
296
|
+
const args = decl.initializer.arguments
|
|
297
|
+
const firstArg = args[0]
|
|
298
|
+
if (
|
|
299
|
+
firstArg &&
|
|
300
|
+
(ts.isArrowFunction(firstArg) ||
|
|
301
|
+
ts.isFunctionExpression(firstArg))
|
|
302
|
+
) {
|
|
303
|
+
// Use the function directly for position calculation
|
|
304
|
+
result.pikkuFuncName = makeDeterministicAnonName(
|
|
305
|
+
firstArg,
|
|
306
|
+
checker
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
// Continue with name extraction
|
|
310
|
+
if (ts.isIdentifier(parent.name)) {
|
|
311
|
+
result.propertyName = parent.name.text
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Check if the variable is exported
|
|
315
|
+
if (
|
|
316
|
+
ts.isVariableDeclaration(decl) &&
|
|
317
|
+
isNamedExport(decl) &&
|
|
318
|
+
ts.isIdentifier(decl.name)
|
|
319
|
+
) {
|
|
320
|
+
result.exportedName = decl.name.text
|
|
321
|
+
} else if (ts.isIdentifier(decl.name)) {
|
|
322
|
+
// If not exported, still capture the variable name
|
|
323
|
+
result.functionName = decl.name.text
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Apply name priority logic
|
|
327
|
+
populateNameByPriority(result)
|
|
328
|
+
return result
|
|
160
329
|
}
|
|
161
330
|
}
|
|
162
|
-
types.push(uniqueName)
|
|
163
331
|
}
|
|
164
332
|
}
|
|
165
333
|
}
|
|
334
|
+
}
|
|
166
335
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
336
|
+
// First, figure out what function we're really dealing with
|
|
337
|
+
let mainFunc = callExpr
|
|
338
|
+
let originalCallExpr = callExpr // Keep track of the original call expression for name extraction
|
|
339
|
+
|
|
340
|
+
// For direct pikku function calls where callExpr is the call expression itself
|
|
341
|
+
if (ts.isCallExpression(callExpr)) {
|
|
342
|
+
const { expression, arguments: args } = callExpr
|
|
343
|
+
|
|
344
|
+
// Check if this is a pikku function call (pikkuFunc, pikkuSessionlessFunc, etc)
|
|
345
|
+
if (ts.isIdentifier(expression) && expression.text.startsWith('pikku')) {
|
|
346
|
+
// Check for object with 'name' property in first argument
|
|
347
|
+
const firstArg = args[0]
|
|
348
|
+
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
349
|
+
for (const prop of firstArg.properties) {
|
|
350
|
+
if (
|
|
351
|
+
ts.isPropertyAssignment(prop) &&
|
|
352
|
+
ts.isIdentifier(prop.name) &&
|
|
353
|
+
prop.name.text === 'name' &&
|
|
354
|
+
ts.isStringLiteral(prop.initializer)
|
|
355
|
+
) {
|
|
356
|
+
// Priority 1: Object with name property
|
|
357
|
+
result.functionName = prop.initializer.text
|
|
358
|
+
break
|
|
359
|
+
}
|
|
360
|
+
}
|
|
171
361
|
}
|
|
172
362
|
|
|
173
|
-
//
|
|
174
|
-
if (
|
|
175
|
-
|
|
363
|
+
// Special handling for pikkuSessionlessFunc pattern - use the arrow function directly
|
|
364
|
+
if (expression.text.startsWith('pikku')) {
|
|
365
|
+
if (args.length > 0) {
|
|
366
|
+
const firstArg = args[0]!
|
|
367
|
+
if (
|
|
368
|
+
ts.isArrowFunction(firstArg) ||
|
|
369
|
+
ts.isFunctionExpression(firstArg)
|
|
370
|
+
) {
|
|
371
|
+
mainFunc = firstArg // Use the arrow function directly instead of the call expression
|
|
372
|
+
}
|
|
373
|
+
}
|
|
176
374
|
}
|
|
375
|
+
}
|
|
177
376
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
377
|
+
// Handle object initializer with a func property (for both patterns)
|
|
378
|
+
if (args.length > 0) {
|
|
379
|
+
const firstArg = args[0]
|
|
380
|
+
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
381
|
+
// Look for func property in the object
|
|
382
|
+
for (const prop of firstArg.properties) {
|
|
383
|
+
if (
|
|
384
|
+
ts.isPropertyAssignment(prop) &&
|
|
385
|
+
ts.isIdentifier(prop.name) &&
|
|
386
|
+
prop.name.text === 'func'
|
|
387
|
+
) {
|
|
388
|
+
if (ts.isIdentifier(prop.initializer)) {
|
|
389
|
+
// func: someFunction - resolve the function
|
|
390
|
+
const funcSym = checker.getSymbolAtLocation(prop.initializer)
|
|
391
|
+
if (funcSym) {
|
|
392
|
+
let resolvedFuncSym = funcSym
|
|
393
|
+
if (resolvedFuncSym.flags & ts.SymbolFlags.Alias) {
|
|
394
|
+
resolvedFuncSym =
|
|
395
|
+
checker.getAliasedSymbol(resolvedFuncSym) ?? resolvedFuncSym
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const funcDecls = resolvedFuncSym.declarations ?? []
|
|
399
|
+
if (funcDecls.length > 0) {
|
|
400
|
+
const funcDecl = funcDecls[0]!
|
|
401
|
+
// Check if it's a pikkuSessionlessFunc
|
|
402
|
+
if (
|
|
403
|
+
ts.isVariableDeclaration(funcDecl) &&
|
|
404
|
+
funcDecl.initializer
|
|
405
|
+
) {
|
|
406
|
+
if (
|
|
407
|
+
ts.isCallExpression(funcDecl.initializer) &&
|
|
408
|
+
ts.isIdentifier(funcDecl.initializer.expression) &&
|
|
409
|
+
funcDecl.initializer.expression.text.startsWith('pikku')
|
|
410
|
+
) {
|
|
411
|
+
const funcArgs = funcDecl.initializer.arguments
|
|
412
|
+
const firstArg = funcArgs[0]
|
|
413
|
+
if (
|
|
414
|
+
firstArg &&
|
|
415
|
+
(ts.isArrowFunction(firstArg) ||
|
|
416
|
+
ts.isFunctionExpression(firstArg))
|
|
417
|
+
) {
|
|
418
|
+
mainFunc = firstArg
|
|
419
|
+
|
|
420
|
+
// Check if the variable is exported
|
|
421
|
+
if (
|
|
422
|
+
isNamedExport(funcDecl) &&
|
|
423
|
+
ts.isIdentifier(funcDecl.name)
|
|
424
|
+
) {
|
|
425
|
+
result.exportedName = funcDecl.name.text
|
|
426
|
+
} else if (ts.isIdentifier(funcDecl.name)) {
|
|
427
|
+
// If not exported, still capture the variable name
|
|
428
|
+
result.functionName = funcDecl.name.text
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
break
|
|
432
|
+
}
|
|
433
|
+
} else if (
|
|
434
|
+
ts.isFunctionExpression(funcDecl.initializer) ||
|
|
435
|
+
ts.isArrowFunction(funcDecl.initializer)
|
|
436
|
+
) {
|
|
437
|
+
mainFunc = funcDecl.initializer
|
|
438
|
+
|
|
439
|
+
// Check if the variable is exported
|
|
440
|
+
if (
|
|
441
|
+
isNamedExport(funcDecl) &&
|
|
442
|
+
ts.isIdentifier(funcDecl.name)
|
|
443
|
+
) {
|
|
444
|
+
result.exportedName = funcDecl.name.text
|
|
445
|
+
} else if (ts.isIdentifier(funcDecl.name)) {
|
|
446
|
+
// If not exported, still capture the variable name
|
|
447
|
+
result.functionName = funcDecl.name.text
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
break
|
|
451
|
+
}
|
|
452
|
+
} else if (ts.isFunctionDeclaration(funcDecl)) {
|
|
453
|
+
mainFunc = funcDecl
|
|
454
|
+
|
|
455
|
+
// Check if the function is exported
|
|
456
|
+
if (
|
|
457
|
+
funcDecl.modifiers?.some(
|
|
458
|
+
(m) => m.kind === ts.SyntaxKind.ExportKeyword
|
|
459
|
+
) &&
|
|
460
|
+
funcDecl.name &&
|
|
461
|
+
ts.isIdentifier(funcDecl.name)
|
|
462
|
+
) {
|
|
463
|
+
result.exportedName = funcDecl.name.text
|
|
464
|
+
} else if (
|
|
465
|
+
funcDecl.name &&
|
|
466
|
+
ts.isIdentifier(funcDecl.name)
|
|
467
|
+
) {
|
|
468
|
+
// If not exported, still capture the function name
|
|
469
|
+
result.functionName = funcDecl.name.text
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
break
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
} else {
|
|
476
|
+
// If we can't resolve the symbol, use the identifier itself
|
|
477
|
+
mainFunc = prop.initializer
|
|
478
|
+
}
|
|
479
|
+
break
|
|
480
|
+
} else if (
|
|
481
|
+
ts.isFunctionExpression(prop.initializer) ||
|
|
482
|
+
ts.isArrowFunction(prop.initializer)
|
|
483
|
+
) {
|
|
484
|
+
// func: () => {} or func: function() {} - use directly
|
|
485
|
+
mainFunc = prop.initializer
|
|
486
|
+
break
|
|
487
|
+
}
|
|
488
|
+
} else if (
|
|
489
|
+
ts.isShorthandPropertyAssignment(prop) &&
|
|
490
|
+
ts.isIdentifier(prop.name) &&
|
|
491
|
+
prop.name.text === 'func'
|
|
492
|
+
) {
|
|
493
|
+
// Handle func shorthand property
|
|
494
|
+
const shorthandSym = checker.getShorthandAssignmentValueSymbol(prop)
|
|
495
|
+
if (
|
|
496
|
+
shorthandSym &&
|
|
497
|
+
shorthandSym.declarations &&
|
|
498
|
+
shorthandSym.declarations.length > 0
|
|
499
|
+
) {
|
|
500
|
+
const shorthandDecl = shorthandSym.declarations[0]
|
|
501
|
+
if (!shorthandDecl) {
|
|
502
|
+
throw new Error('No shorthand declaration found')
|
|
503
|
+
}
|
|
504
|
+
if (
|
|
505
|
+
ts.isVariableDeclaration(shorthandDecl) &&
|
|
506
|
+
shorthandDecl.initializer
|
|
507
|
+
) {
|
|
508
|
+
if (
|
|
509
|
+
ts.isCallExpression(shorthandDecl.initializer) &&
|
|
510
|
+
ts.isIdentifier(shorthandDecl.initializer.expression) &&
|
|
511
|
+
shorthandDecl.initializer.expression.text.startsWith('pikku')
|
|
512
|
+
) {
|
|
513
|
+
const args = shorthandDecl.initializer.arguments
|
|
514
|
+
const firstArg = args[0]
|
|
515
|
+
if (
|
|
516
|
+
firstArg &&
|
|
517
|
+
(ts.isArrowFunction(firstArg) ||
|
|
518
|
+
ts.isFunctionExpression(firstArg))
|
|
519
|
+
) {
|
|
520
|
+
mainFunc = firstArg
|
|
521
|
+
|
|
522
|
+
// Check if the variable is exported
|
|
523
|
+
if (
|
|
524
|
+
isNamedExport(shorthandDecl) &&
|
|
525
|
+
ts.isIdentifier(shorthandDecl.name)
|
|
526
|
+
) {
|
|
527
|
+
result.exportedName = shorthandDecl.name.text
|
|
528
|
+
} else if (ts.isIdentifier(shorthandDecl.name)) {
|
|
529
|
+
// If not exported, still capture the variable name
|
|
530
|
+
result.functionName = shorthandDecl.name.text
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
break
|
|
534
|
+
}
|
|
535
|
+
} else if (
|
|
536
|
+
ts.isFunctionExpression(shorthandDecl.initializer) ||
|
|
537
|
+
ts.isArrowFunction(shorthandDecl.initializer)
|
|
538
|
+
) {
|
|
539
|
+
mainFunc = shorthandDecl.initializer
|
|
540
|
+
|
|
541
|
+
// Check if the variable is exported
|
|
542
|
+
if (
|
|
543
|
+
isNamedExport(shorthandDecl) &&
|
|
544
|
+
ts.isIdentifier(shorthandDecl.name)
|
|
545
|
+
) {
|
|
546
|
+
result.exportedName = shorthandDecl.name.text
|
|
547
|
+
} else if (ts.isIdentifier(shorthandDecl.name)) {
|
|
548
|
+
// If not exported, still capture the variable name
|
|
549
|
+
result.functionName = shorthandDecl.name.text
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
break
|
|
553
|
+
}
|
|
554
|
+
} else if (ts.isFunctionDeclaration(shorthandDecl)) {
|
|
555
|
+
mainFunc = shorthandDecl
|
|
556
|
+
|
|
557
|
+
// Check if the function is exported
|
|
558
|
+
if (
|
|
559
|
+
shorthandDecl.modifiers?.some(
|
|
560
|
+
(m) => m.kind === ts.SyntaxKind.ExportKeyword
|
|
561
|
+
) &&
|
|
562
|
+
shorthandDecl.name &&
|
|
563
|
+
ts.isIdentifier(shorthandDecl.name)
|
|
564
|
+
) {
|
|
565
|
+
result.exportedName = shorthandDecl.name.text
|
|
566
|
+
} else if (
|
|
567
|
+
shorthandDecl.name &&
|
|
568
|
+
ts.isIdentifier(shorthandDecl.name)
|
|
569
|
+
) {
|
|
570
|
+
// If not exported, still capture the function name
|
|
571
|
+
result.functionName = shorthandDecl.name.text
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
break
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
185
579
|
}
|
|
186
580
|
}
|
|
187
581
|
}
|
|
582
|
+
// Handle direct identifier case
|
|
583
|
+
else if (ts.isIdentifier(callExpr)) {
|
|
584
|
+
const sym = checker.getSymbolAtLocation(callExpr)
|
|
585
|
+
if (sym) {
|
|
586
|
+
let resolvedSym = sym
|
|
587
|
+
if (resolvedSym.flags & ts.SymbolFlags.Alias) {
|
|
588
|
+
resolvedSym = checker.getAliasedSymbol(resolvedSym) ?? resolvedSym
|
|
589
|
+
}
|
|
188
590
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
591
|
+
const decls = resolvedSym.declarations ?? []
|
|
592
|
+
if (decls.length > 0) {
|
|
593
|
+
const decl = decls[0]
|
|
594
|
+
if (!decl) {
|
|
595
|
+
throw new Error('No declaration found')
|
|
596
|
+
}
|
|
597
|
+
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
598
|
+
if (
|
|
599
|
+
ts.isCallExpression(decl.initializer) &&
|
|
600
|
+
ts.isIdentifier(decl.initializer.expression) &&
|
|
601
|
+
decl.initializer.expression.text.startsWith('pikku')
|
|
602
|
+
) {
|
|
603
|
+
// Check for object with 'name' property in first argument
|
|
604
|
+
const firstArg = decl.initializer.arguments[0]
|
|
605
|
+
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
606
|
+
for (const prop of firstArg.properties) {
|
|
607
|
+
if (
|
|
608
|
+
ts.isPropertyAssignment(prop) &&
|
|
609
|
+
ts.isIdentifier(prop.name) &&
|
|
610
|
+
prop.name.text === 'name' &&
|
|
611
|
+
ts.isStringLiteral(prop.initializer)
|
|
612
|
+
) {
|
|
613
|
+
// Priority 1: Object with name property
|
|
614
|
+
result.functionName = prop.initializer.text
|
|
615
|
+
break
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
192
619
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
)
|
|
203
|
-
if (!property) {
|
|
204
|
-
console.error(`Missing property '${name}' in object`)
|
|
205
|
-
return null
|
|
206
|
-
}
|
|
207
|
-
return property
|
|
208
|
-
}
|
|
620
|
+
if (decl.initializer.expression.text.startsWith('pikku')) {
|
|
621
|
+
if (
|
|
622
|
+
firstArg &&
|
|
623
|
+
(ts.isArrowFunction(firstArg) ||
|
|
624
|
+
ts.isFunctionExpression(firstArg))
|
|
625
|
+
) {
|
|
626
|
+
mainFunc = firstArg
|
|
627
|
+
}
|
|
628
|
+
}
|
|
209
629
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
630
|
+
// Check if the variable is exported
|
|
631
|
+
if (isNamedExport(decl) && ts.isIdentifier(decl.name)) {
|
|
632
|
+
result.exportedName = decl.name.text
|
|
633
|
+
} else if (ts.isIdentifier(decl.name)) {
|
|
634
|
+
// If not explicitly set by name property above, set functionName
|
|
635
|
+
if (!result.functionName) {
|
|
636
|
+
result.functionName = decl.name.text
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
} else if (
|
|
640
|
+
ts.isFunctionExpression(decl.initializer) ||
|
|
641
|
+
ts.isArrowFunction(decl.initializer)
|
|
642
|
+
) {
|
|
643
|
+
mainFunc = decl.initializer
|
|
644
|
+
|
|
645
|
+
// Check if the variable is exported
|
|
646
|
+
if (isNamedExport(decl) && ts.isIdentifier(decl.name)) {
|
|
647
|
+
result.exportedName = decl.name.text
|
|
648
|
+
} else if (ts.isIdentifier(decl.name)) {
|
|
649
|
+
result.functionName = decl.name.text
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
} else if (ts.isFunctionDeclaration(decl)) {
|
|
653
|
+
mainFunc = decl
|
|
654
|
+
|
|
655
|
+
// Check if the function is exported
|
|
656
|
+
if (
|
|
657
|
+
decl.modifiers?.some(
|
|
658
|
+
(m) => m.kind === ts.SyntaxKind.ExportKeyword
|
|
659
|
+
) &&
|
|
660
|
+
decl.name &&
|
|
661
|
+
ts.isIdentifier(decl.name)
|
|
662
|
+
) {
|
|
663
|
+
result.exportedName = decl.name.text
|
|
664
|
+
} else if (decl.name && ts.isIdentifier(decl.name)) {
|
|
665
|
+
result.functionName = decl.name.text
|
|
666
|
+
}
|
|
667
|
+
}
|
|
220
668
|
}
|
|
221
669
|
}
|
|
222
|
-
return types.length > 0 ? types : null
|
|
223
670
|
}
|
|
224
671
|
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
if (
|
|
232
|
-
|
|
672
|
+
// Now generate the deterministic function name based on the resolved function
|
|
673
|
+
result.pikkuFuncName = makeDeterministicAnonName(mainFunc, checker)
|
|
674
|
+
|
|
675
|
+
// Continue with regular name extraction for remaining cases
|
|
676
|
+
// 1) const foo = pikkuFunc(...)
|
|
677
|
+
if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
|
|
678
|
+
if (isNamedExport(parent)) {
|
|
679
|
+
result.exportedName = parent.name.text
|
|
680
|
+
} else {
|
|
681
|
+
// Still capture the variable name even if not exported
|
|
682
|
+
result.functionName = parent.name.text
|
|
233
683
|
}
|
|
234
684
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
685
|
+
// 2) { foo: pikkuFunc(...) }
|
|
686
|
+
else if (ts.isPropertyAssignment(parent) && ts.isIdentifier(parent.name)) {
|
|
687
|
+
result.propertyName = parent.name.text
|
|
688
|
+
}
|
|
689
|
+
// 2b) Handle shorthand property { foo } - which is equivalent to { foo: foo }
|
|
690
|
+
else if (
|
|
691
|
+
ts.isShorthandPropertyAssignment(parent) &&
|
|
692
|
+
ts.isIdentifier(parent.name)
|
|
693
|
+
) {
|
|
694
|
+
result.propertyName = parent.name.text
|
|
695
|
+
}
|
|
696
|
+
// 3) Handle any remaining cases for pikkuFunc({ name: '…', func: … })
|
|
697
|
+
else if (ts.isCallExpression(originalCallExpr)) {
|
|
698
|
+
const firstArg = originalCallExpr.arguments[0]
|
|
699
|
+
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
700
|
+
for (const prop of firstArg.properties) {
|
|
701
|
+
if (
|
|
702
|
+
ts.isPropertyAssignment(prop) &&
|
|
703
|
+
ts.isIdentifier(prop.name) &&
|
|
704
|
+
prop.name.text === 'name' &&
|
|
705
|
+
ts.isStringLiteral(prop.initializer) &&
|
|
706
|
+
!result.functionName // Only set if not already set
|
|
707
|
+
) {
|
|
708
|
+
result.functionName = prop.initializer.text
|
|
709
|
+
break
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
239
713
|
}
|
|
240
714
|
|
|
241
|
-
|
|
715
|
+
// Apply name priority logic
|
|
716
|
+
populateNameByPriority(result)
|
|
717
|
+
return result
|
|
242
718
|
}
|
|
243
719
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
inputIndex,
|
|
252
|
-
outputIndex,
|
|
253
|
-
}: {
|
|
254
|
-
typesMap: TypesMap
|
|
255
|
-
subFunctionName?: string
|
|
256
|
-
funcName: string
|
|
257
|
-
inputIndex: number
|
|
258
|
-
outputIndex: number
|
|
720
|
+
/**
|
|
721
|
+
* Helper function to populate the 'name' field based on priority
|
|
722
|
+
*/
|
|
723
|
+
function populateNameByPriority(result: ExtractedFunctionName): void {
|
|
724
|
+
// Priority 1: If we have a functionName (from name property or variable name), use that
|
|
725
|
+
if (result.functionName) {
|
|
726
|
+
result.name = result.functionName
|
|
259
727
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
inputs: null,
|
|
264
|
-
outputTypes: [],
|
|
265
|
-
outputs: null,
|
|
266
|
-
type: null,
|
|
728
|
+
// Priority 2: If we have an exported name, use that
|
|
729
|
+
else if (result.exportedName) {
|
|
730
|
+
result.name = result.exportedName
|
|
267
731
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
return result
|
|
732
|
+
// Priority 3: If we have a property name, use that
|
|
733
|
+
else if (result.propertyName) {
|
|
734
|
+
result.name = result.propertyName
|
|
272
735
|
}
|
|
736
|
+
// Fallback: Use the deterministic name, but we could shorten it in the future
|
|
737
|
+
else {
|
|
738
|
+
// For now, just use the full pikkuFuncName
|
|
739
|
+
result.name = result.pikkuFuncName
|
|
740
|
+
|
|
741
|
+
// Alternative: extract just the filename and line/column from pikkuFuncName
|
|
742
|
+
// const nameParts = result.pikkuFuncName.split('_');
|
|
743
|
+
// if (nameParts.length >= 3) {
|
|
744
|
+
// // Extract just filename + line/column info
|
|
745
|
+
// result.name = `${nameParts[1]}_${nameParts[2]}`;
|
|
746
|
+
// }
|
|
747
|
+
}
|
|
748
|
+
}
|
|
273
749
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
750
|
+
/**
|
|
751
|
+
* Helper function to check if a variable declaration is a named export
|
|
752
|
+
*/
|
|
753
|
+
function isNamedExport(declaration: ts.VariableDeclaration): boolean {
|
|
754
|
+
let parent: any = declaration.parent
|
|
755
|
+
if (!parent) return false
|
|
756
|
+
|
|
757
|
+
// Check if it's part of a variable declaration list
|
|
758
|
+
if (ts.isVariableDeclarationList(parent)) {
|
|
759
|
+
parent = parent.parent
|
|
760
|
+
if (!parent) return false
|
|
761
|
+
|
|
762
|
+
// Check if it's in an export declaration
|
|
763
|
+
if (ts.isVariableStatement(parent)) {
|
|
764
|
+
return (
|
|
765
|
+
parent.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ??
|
|
766
|
+
false
|
|
767
|
+
)
|
|
284
768
|
}
|
|
285
769
|
}
|
|
286
|
-
// Handle regular property assignment
|
|
287
|
-
else if (ts.isPropertyAssignment(property)) {
|
|
288
|
-
if (ts.isObjectLiteralExpression(property.initializer)) {
|
|
289
|
-
return getFunctionTypes(checker, property.initializer, {
|
|
290
|
-
typesMap,
|
|
291
|
-
funcName,
|
|
292
|
-
subFunctionName: 'func',
|
|
293
|
-
inputIndex,
|
|
294
|
-
outputIndex,
|
|
295
|
-
})
|
|
296
|
-
}
|
|
297
770
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
771
|
+
return false
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// Until here
|
|
775
|
+
export const extractTypeKeys = (type: ts.Type): string[] => {
|
|
776
|
+
return type.getProperties().map((symbol) => symbol.getName())
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
export function getPropertyAssignmentInitializer(
|
|
780
|
+
obj: ts.ObjectLiteralExpression,
|
|
781
|
+
propName: string,
|
|
782
|
+
followShorthand = false,
|
|
783
|
+
checker?: ts.TypeChecker
|
|
784
|
+
): ts.Expression | undefined {
|
|
785
|
+
for (const prop of obj.properties) {
|
|
786
|
+
// ① foo: () => {}
|
|
787
|
+
if (
|
|
788
|
+
ts.isPropertyAssignment(prop) &&
|
|
789
|
+
ts.isIdentifier(prop.name) &&
|
|
790
|
+
prop.name.text === propName
|
|
791
|
+
) {
|
|
792
|
+
return prop.initializer
|
|
303
793
|
}
|
|
304
|
-
}
|
|
305
794
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
795
|
+
// ② foo() { … }
|
|
796
|
+
if (
|
|
797
|
+
ts.isMethodDeclaration(prop) &&
|
|
798
|
+
ts.isIdentifier(prop.name) &&
|
|
799
|
+
prop.name.text === propName
|
|
800
|
+
) {
|
|
801
|
+
return prop.name // the method node *is* the function
|
|
802
|
+
}
|
|
310
803
|
|
|
311
|
-
|
|
804
|
+
// ③ { foo } (shorthand)
|
|
805
|
+
if (
|
|
806
|
+
followShorthand &&
|
|
807
|
+
ts.isShorthandPropertyAssignment(prop) &&
|
|
808
|
+
prop.name.text === propName
|
|
809
|
+
) {
|
|
810
|
+
if (!checker) return prop.name // best effort without a checker
|
|
811
|
+
|
|
812
|
+
let sym = checker.getSymbolAtLocation(prop.name)
|
|
813
|
+
if (sym && sym.flags & ts.SymbolFlags.Alias) {
|
|
814
|
+
sym = checker.getAliasedSymbol(sym)
|
|
815
|
+
}
|
|
312
816
|
|
|
313
|
-
|
|
314
|
-
const typeArguments = getTypeArgumentsOfType(checker, type)
|
|
817
|
+
const decl = sym?.declarations?.[0]
|
|
315
818
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
819
|
+
// const foo = () => {}
|
|
820
|
+
if (
|
|
821
|
+
decl &&
|
|
822
|
+
ts.isVariableDeclaration(decl) &&
|
|
823
|
+
decl.initializer &&
|
|
824
|
+
(ts.isArrowFunction(decl.initializer) ||
|
|
825
|
+
ts.isFunctionExpression(decl.initializer))
|
|
826
|
+
) {
|
|
827
|
+
return decl.initializer
|
|
828
|
+
}
|
|
324
829
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
result.inputTypes = types
|
|
335
|
-
} else {
|
|
336
|
-
console.log(`No input defined for ${funcName}`)
|
|
337
|
-
}
|
|
830
|
+
// function foo() {}
|
|
831
|
+
if (
|
|
832
|
+
decl &&
|
|
833
|
+
(ts.isFunctionDeclaration(decl) ||
|
|
834
|
+
ts.isArrowFunction(decl) ||
|
|
835
|
+
ts.isFunctionExpression(decl))
|
|
836
|
+
) {
|
|
837
|
+
return decl as ts.Expression
|
|
838
|
+
}
|
|
338
839
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
typesMap,
|
|
343
|
-
'Output',
|
|
344
|
-
funcName,
|
|
345
|
-
typeArguments[outputIndex]!
|
|
346
|
-
)
|
|
347
|
-
result.outputs = names
|
|
348
|
-
result.outputTypes = types
|
|
349
|
-
} else {
|
|
350
|
-
console.info(`No output defined for ${funcName}`)
|
|
840
|
+
// fallback – just give back the identifier
|
|
841
|
+
return prop.name
|
|
842
|
+
}
|
|
351
843
|
}
|
|
352
844
|
|
|
353
|
-
return
|
|
845
|
+
return undefined
|
|
354
846
|
}
|
|
355
847
|
|
|
356
848
|
export const matchesFilters = (
|