@codeflow-map/core 0.1.0
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/README.md +158 -0
- package/dist/analyzer/extractorUtils.d.ts +50 -0
- package/dist/analyzer/extractorUtils.js +247 -0
- package/dist/analyzer/index.d.ts +9 -0
- package/dist/analyzer/index.js +149 -0
- package/dist/analyzer/languages/go.d.ts +2 -0
- package/dist/analyzer/languages/go.js +232 -0
- package/dist/analyzer/languages/javascript.d.ts +2 -0
- package/dist/analyzer/languages/javascript.js +265 -0
- package/dist/analyzer/languages/jsx.d.ts +2 -0
- package/dist/analyzer/languages/jsx.js +275 -0
- package/dist/analyzer/languages/python.d.ts +2 -0
- package/dist/analyzer/languages/python.js +236 -0
- package/dist/analyzer/languages/tsx.d.ts +2 -0
- package/dist/analyzer/languages/tsx.js +358 -0
- package/dist/analyzer/languages/typescript.d.ts +2 -0
- package/dist/analyzer/languages/typescript.js +351 -0
- package/dist/analyzer/treeSitter.d.ts +4 -0
- package/dist/analyzer/treeSitter.js +62 -0
- package/dist/graph/callGraphBuilder.d.ts +2 -0
- package/dist/graph/callGraphBuilder.js +58 -0
- package/dist/graph/entryPointDetector.d.ts +2 -0
- package/dist/graph/entryPointDetector.js +11 -0
- package/dist/graph/flowPartitioner.d.ts +5 -0
- package/dist/graph/flowPartitioner.js +101 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +22 -0
- package/dist/types.d.ts +62 -0
- package/dist/types.js +13 -0
- package/package.json +48 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.goAnalyzer = void 0;
|
|
4
|
+
const extractorUtils_1 = require("../extractorUtils");
|
|
5
|
+
exports.goAnalyzer = {
|
|
6
|
+
functionQuery: `
|
|
7
|
+
(function_declaration
|
|
8
|
+
name: (identifier) @fn.name
|
|
9
|
+
parameters: (parameter_list) @fn.params
|
|
10
|
+
result: [(parameter_list) (type_identifier)]? @fn.return_type) @fn.decl
|
|
11
|
+
|
|
12
|
+
(method_declaration
|
|
13
|
+
name: (field_identifier) @fn.name
|
|
14
|
+
parameters: (parameter_list) @fn.params
|
|
15
|
+
result: [(parameter_list) (type_identifier)]? @fn.return_type) @fn.decl
|
|
16
|
+
|
|
17
|
+
(func_literal
|
|
18
|
+
parameters: (parameter_list) @fn.params
|
|
19
|
+
result: [(parameter_list) (type_identifier)]? @fn.return_type) @fn.decl
|
|
20
|
+
`,
|
|
21
|
+
callQuery: `
|
|
22
|
+
(call_expression
|
|
23
|
+
function: [(identifier) (selector_expression field: (field_identifier))] @call.name) @call.expr
|
|
24
|
+
|
|
25
|
+
(go_statement
|
|
26
|
+
(call_expression
|
|
27
|
+
function: [(identifier) (selector_expression field: (field_identifier))] @call.name)) @call.expr
|
|
28
|
+
|
|
29
|
+
(go_statement
|
|
30
|
+
(call_expression
|
|
31
|
+
function: (func_literal) @call.anon_fn)) @call.expr
|
|
32
|
+
`,
|
|
33
|
+
extractFunction(match, filePath, languageId) {
|
|
34
|
+
const declCapture = match.captures.find((c) => c.name === 'fn.decl');
|
|
35
|
+
if (!declCapture)
|
|
36
|
+
return null;
|
|
37
|
+
const nameCapture = match.captures.find((c) => c.name === 'fn.name');
|
|
38
|
+
let fnName;
|
|
39
|
+
let kind = 'function';
|
|
40
|
+
let isExported = false;
|
|
41
|
+
if (nameCapture) {
|
|
42
|
+
fnName = nameCapture.node.text;
|
|
43
|
+
isExported = fnName.length > 0 && fnName[0] === fnName[0].toUpperCase();
|
|
44
|
+
if (declCapture.node.type === 'method_declaration') {
|
|
45
|
+
kind = 'method';
|
|
46
|
+
const receiver = declCapture.node.childForFieldName('receiver');
|
|
47
|
+
if (receiver) {
|
|
48
|
+
for (const child of receiver.namedChildren) {
|
|
49
|
+
if (child.type === 'parameter_declaration') {
|
|
50
|
+
const typeNode = child.childForFieldName('type');
|
|
51
|
+
if (typeNode) {
|
|
52
|
+
fnName = `${typeNode.text.replace(/^\*/, '')}.${fnName}`;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (declCapture.node.type === 'func_literal') {
|
|
61
|
+
// func_literal: find variable name from short_var_declaration or use anonymous
|
|
62
|
+
fnName = `anonymous_${declCapture.node.startPosition.row}`;
|
|
63
|
+
const parent = declCapture.node.parent;
|
|
64
|
+
if (parent?.type === 'expression_list') {
|
|
65
|
+
const grandparent = parent.parent;
|
|
66
|
+
if (grandparent?.type === 'short_var_declaration') {
|
|
67
|
+
const left = grandparent.childForFieldName('left');
|
|
68
|
+
const nameNode = left?.namedChildren?.find((n) => n.type === 'identifier');
|
|
69
|
+
if (nameNode)
|
|
70
|
+
fnName = nameNode.text;
|
|
71
|
+
}
|
|
72
|
+
else if (grandparent?.type === 'var_spec') {
|
|
73
|
+
const nameNode = grandparent.childForFieldName('name');
|
|
74
|
+
if (nameNode)
|
|
75
|
+
fnName = nameNode.text;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Prefix with enclosing function/method
|
|
79
|
+
let current = declCapture.node.parent;
|
|
80
|
+
while (current) {
|
|
81
|
+
if (current.type === 'function_declaration') {
|
|
82
|
+
const name = current.childForFieldName('name');
|
|
83
|
+
if (name)
|
|
84
|
+
fnName = `${name.text}.${fnName}`;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
if (current.type === 'method_declaration') {
|
|
88
|
+
const name = current.childForFieldName('name');
|
|
89
|
+
if (name) {
|
|
90
|
+
let prefix = name.text;
|
|
91
|
+
const recv = current.childForFieldName('receiver');
|
|
92
|
+
if (recv) {
|
|
93
|
+
for (const child of recv.namedChildren) {
|
|
94
|
+
if (child.type === 'parameter_declaration') {
|
|
95
|
+
const typeNode = child.childForFieldName('type');
|
|
96
|
+
if (typeNode) {
|
|
97
|
+
prefix = `${typeNode.text.replace(/^\*/, '')}.${prefix}`;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
fnName = `${prefix}.${fnName}`;
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
current = current.parent;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const paramsCapture = match.captures.find((c) => c.name === 'fn.params');
|
|
114
|
+
const returnCapture = match.captures.find((c) => c.name === 'fn.return_type');
|
|
115
|
+
// Parse parameters — only collect identifier children, skip all type nodes
|
|
116
|
+
const paramsList = [];
|
|
117
|
+
if (paramsCapture && paramsCapture.node) {
|
|
118
|
+
for (const child of paramsCapture.node.namedChildren) {
|
|
119
|
+
if (child.type === 'parameter_declaration') {
|
|
120
|
+
const typeNode = child.childForFieldName('type');
|
|
121
|
+
const typeStr = typeNode ? typeNode.text : null;
|
|
122
|
+
const nameNodes = child.namedChildren.filter((n) => n.type === 'identifier');
|
|
123
|
+
if (nameNodes.length > 0) {
|
|
124
|
+
for (const n of nameNodes) {
|
|
125
|
+
paramsList.push({ name: n.text, type: typeStr });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
paramsList.push({ name: child.text, type: null });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else if (child.type === 'variadic_parameter_declaration') {
|
|
133
|
+
const nameNode = child.namedChildren.find((n) => n.type === 'identifier');
|
|
134
|
+
const typeNode = child.childForFieldName('type');
|
|
135
|
+
paramsList.push({
|
|
136
|
+
name: nameNode ? nameNode.text : child.text,
|
|
137
|
+
type: typeNode ? `...${typeNode.text}` : null
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
let finalReturnType = returnCapture ? returnCapture.node.text : null;
|
|
143
|
+
if (!finalReturnType) {
|
|
144
|
+
const returnValues = (0, extractorUtils_1.getReturnValues)(declCapture.node, extractorUtils_1.GO_NESTED_FN_TYPES);
|
|
145
|
+
if (returnValues.length > 0) {
|
|
146
|
+
finalReturnType = returnValues.join(' | ');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
id: `${filePath}::${fnName}::${declCapture.node.startPosition.row}`,
|
|
151
|
+
name: fnName,
|
|
152
|
+
filePath,
|
|
153
|
+
startLine: declCapture.node.startPosition.row,
|
|
154
|
+
endLine: declCapture.node.endPosition.row,
|
|
155
|
+
params: paramsList,
|
|
156
|
+
returnType: finalReturnType,
|
|
157
|
+
isAsync: false,
|
|
158
|
+
isExported,
|
|
159
|
+
isEntryPoint: false,
|
|
160
|
+
language: languageId,
|
|
161
|
+
kind
|
|
162
|
+
};
|
|
163
|
+
},
|
|
164
|
+
extractCall(match, filePath) {
|
|
165
|
+
const nameCapture = match.captures.find((c) => c.name === 'call.name');
|
|
166
|
+
const anonCapture = match.captures.find((c) => c.name === 'call.anon_fn');
|
|
167
|
+
const exprCapture = match.captures.find((c) => c.name === 'call.expr');
|
|
168
|
+
if (!exprCapture)
|
|
169
|
+
return null;
|
|
170
|
+
// Handle go func(){...}() — immediately-invoked anonymous goroutine
|
|
171
|
+
if (anonCapture && exprCapture.node.type === 'go_statement') {
|
|
172
|
+
const funcLit = anonCapture.node;
|
|
173
|
+
let anonName = `anonymous_${funcLit.startPosition.row}`;
|
|
174
|
+
// Prefix with enclosing function/method name to match FunctionNode naming
|
|
175
|
+
let current = funcLit.parent;
|
|
176
|
+
while (current) {
|
|
177
|
+
if (current.type === 'function_declaration') {
|
|
178
|
+
const name = current.childForFieldName('name');
|
|
179
|
+
if (name)
|
|
180
|
+
anonName = `${name.text}.${anonName}`;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
if (current.type === 'method_declaration') {
|
|
184
|
+
const name = current.childForFieldName('name');
|
|
185
|
+
if (name) {
|
|
186
|
+
let prefix = name.text;
|
|
187
|
+
const recv = current.childForFieldName('receiver');
|
|
188
|
+
if (recv) {
|
|
189
|
+
for (const child of recv.namedChildren) {
|
|
190
|
+
if (child.type === 'parameter_declaration') {
|
|
191
|
+
const typeNode = child.childForFieldName('type');
|
|
192
|
+
if (typeNode) {
|
|
193
|
+
prefix = `${typeNode.text.replace(/^\*/, '')}.${prefix}`;
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
anonName = `${prefix}.${anonName}`;
|
|
200
|
+
}
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
current = current.parent;
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
callerFilePath: filePath,
|
|
207
|
+
calleeName: anonName,
|
|
208
|
+
line: exprCapture.node.startPosition.row,
|
|
209
|
+
callType: 'goroutine'
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
if (!nameCapture)
|
|
213
|
+
return null;
|
|
214
|
+
// Skip regular call_expression inside go_statement — the go_statement pattern handles it
|
|
215
|
+
if (exprCapture.node.type === 'call_expression' && exprCapture.node.parent?.type === 'go_statement') {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
let calleeName = nameCapture.node.text;
|
|
219
|
+
if (nameCapture.node.type === 'selector_expression') {
|
|
220
|
+
const field = nameCapture.node.childForFieldName('field');
|
|
221
|
+
if (field)
|
|
222
|
+
calleeName = field.text;
|
|
223
|
+
}
|
|
224
|
+
const isGoroutine = exprCapture.node.type === 'go_statement';
|
|
225
|
+
return {
|
|
226
|
+
callerFilePath: filePath,
|
|
227
|
+
calleeName,
|
|
228
|
+
line: exprCapture.node.startPosition.row,
|
|
229
|
+
...(isGoroutine ? { callType: 'goroutine' } : {})
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
};
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.javascriptAnalyzer = void 0;
|
|
4
|
+
const extractorUtils_1 = require("../extractorUtils");
|
|
5
|
+
exports.javascriptAnalyzer = {
|
|
6
|
+
functionQuery: `
|
|
7
|
+
(function_declaration
|
|
8
|
+
name: (identifier) @fn.name
|
|
9
|
+
parameters: (formal_parameters) @fn.params) @fn.decl
|
|
10
|
+
|
|
11
|
+
(lexical_declaration
|
|
12
|
+
(variable_declarator
|
|
13
|
+
name: (identifier) @fn.name
|
|
14
|
+
value: [(arrow_function) (function_expression)] @fn.decl))
|
|
15
|
+
|
|
16
|
+
(export_statement
|
|
17
|
+
declaration: (lexical_declaration
|
|
18
|
+
(variable_declarator
|
|
19
|
+
name: (identifier) @fn.name
|
|
20
|
+
value: [(arrow_function) (function_expression)] @fn.decl)))
|
|
21
|
+
|
|
22
|
+
(method_definition
|
|
23
|
+
name: (property_identifier) @fn.name
|
|
24
|
+
parameters: (formal_parameters) @fn.params) @fn.decl
|
|
25
|
+
|
|
26
|
+
(call_expression
|
|
27
|
+
function: (identifier) @hook.name
|
|
28
|
+
arguments: (arguments
|
|
29
|
+
[(arrow_function) (function_expression)] @fn.decl)
|
|
30
|
+
(#match? @hook.name "^use"))
|
|
31
|
+
|
|
32
|
+
(generator_function_declaration
|
|
33
|
+
name: (identifier) @fn.name
|
|
34
|
+
parameters: (formal_parameters) @fn.params) @fn.decl
|
|
35
|
+
|
|
36
|
+
(lexical_declaration
|
|
37
|
+
(variable_declarator
|
|
38
|
+
name: (identifier) @fn.name
|
|
39
|
+
value: (generator_function) @fn.decl))
|
|
40
|
+
|
|
41
|
+
(export_statement
|
|
42
|
+
declaration: (lexical_declaration
|
|
43
|
+
(variable_declarator
|
|
44
|
+
name: (identifier) @fn.name
|
|
45
|
+
value: (generator_function) @fn.decl)))
|
|
46
|
+
|
|
47
|
+
(function_expression
|
|
48
|
+
name: (identifier) @fn.name
|
|
49
|
+
parameters: (formal_parameters) @fn.params) @fn.decl
|
|
50
|
+
|
|
51
|
+
(lexical_declaration
|
|
52
|
+
(variable_declarator
|
|
53
|
+
name: (identifier) @fn.name
|
|
54
|
+
value: (call_expression
|
|
55
|
+
function: [(parenthesized_expression
|
|
56
|
+
[(function_expression)(arrow_function)] @fn.decl)
|
|
57
|
+
(arrow_function) @fn.decl
|
|
58
|
+
(function_expression) @fn.decl])))
|
|
59
|
+
|
|
60
|
+
(expression_statement
|
|
61
|
+
(call_expression
|
|
62
|
+
function: (parenthesized_expression
|
|
63
|
+
[(function_expression)(arrow_function)] @fn.decl)))
|
|
64
|
+
|
|
65
|
+
(assignment_expression
|
|
66
|
+
left: (member_expression
|
|
67
|
+
object: (identifier) @worker.obj
|
|
68
|
+
property: (property_identifier) @worker.prop)
|
|
69
|
+
right: [(arrow_function) (function_expression)] @worker.fn
|
|
70
|
+
(#match? @worker.obj "^self$")
|
|
71
|
+
(#match? @worker.prop "^onmessage$"))
|
|
72
|
+
|
|
73
|
+
(call_expression
|
|
74
|
+
function: (member_expression
|
|
75
|
+
object: (identifier) @worker.obj
|
|
76
|
+
property: (property_identifier) @worker.method)
|
|
77
|
+
arguments: (arguments
|
|
78
|
+
(string) @worker.event
|
|
79
|
+
[(arrow_function) (function_expression)] @worker.fn)
|
|
80
|
+
(#match? @worker.obj "^self$")
|
|
81
|
+
(#match? @worker.method "^addEventListener$")
|
|
82
|
+
(#match? @worker.event "message"))
|
|
83
|
+
`,
|
|
84
|
+
callQuery: `
|
|
85
|
+
(call_expression
|
|
86
|
+
function: [(identifier)(member_expression)] @call.name) @call.expr
|
|
87
|
+
|
|
88
|
+
(new_expression
|
|
89
|
+
constructor: (identifier) @call.name) @call.expr
|
|
90
|
+
|
|
91
|
+
(call_expression
|
|
92
|
+
function: (member_expression
|
|
93
|
+
property: (property_identifier) @call.name
|
|
94
|
+
(#match? @call.name "^(then|catch|finally)$"))) @call.expr
|
|
95
|
+
`,
|
|
96
|
+
extractFunction(match, filePath, languageId) {
|
|
97
|
+
const declCapture = match.captures.find((c) => c.name === 'fn.decl');
|
|
98
|
+
if (!declCapture) {
|
|
99
|
+
const workerFn = match.captures.find((c) => c.name === 'worker.fn');
|
|
100
|
+
if (workerFn) {
|
|
101
|
+
const workerProp = match.captures.find((c) => c.name === 'worker.prop');
|
|
102
|
+
const node = workerFn.node;
|
|
103
|
+
const rawName = workerProp ? 'onmessage_handler' : `message_handler_${node.startPosition.row}`;
|
|
104
|
+
const paramsList = (0, extractorUtils_1.getParamsFromFunctionNode)(node, false);
|
|
105
|
+
return {
|
|
106
|
+
id: `${filePath}::${rawName}::${node.startPosition.row}`,
|
|
107
|
+
name: rawName,
|
|
108
|
+
filePath,
|
|
109
|
+
startLine: node.startPosition.row,
|
|
110
|
+
endLine: node.endPosition.row,
|
|
111
|
+
params: paramsList,
|
|
112
|
+
returnType: null,
|
|
113
|
+
isAsync: (0, extractorUtils_1.checkIsAsync)(node),
|
|
114
|
+
isExported: false,
|
|
115
|
+
isEntryPoint: true,
|
|
116
|
+
language: languageId,
|
|
117
|
+
kind: 'function'
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
const nameCapture = match.captures.find((c) => c.name === 'fn.name');
|
|
123
|
+
const hookNameCapture = match.captures.find((c) => c.name === 'hook.name');
|
|
124
|
+
let rawName = "anonymous";
|
|
125
|
+
let kind = 'function';
|
|
126
|
+
let parentFunctionId;
|
|
127
|
+
if (nameCapture) {
|
|
128
|
+
rawName = nameCapture.node.text;
|
|
129
|
+
if (declCapture.node.type === 'function_expression' && nameCapture.node.parent?.id === declCapture.node.id) {
|
|
130
|
+
if (declCapture.node.parent?.type === 'variable_declarator') {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
parentFunctionId = (0, extractorUtils_1.getEnclosingFunctionId)(declCapture.node, filePath) ?? undefined;
|
|
134
|
+
}
|
|
135
|
+
if (declCapture.node.type === 'method_definition') {
|
|
136
|
+
kind = 'method';
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else if (hookNameCapture) {
|
|
140
|
+
const startLine = declCapture.node.startPosition.row;
|
|
141
|
+
rawName = `${hookNameCapture.node.text}_callback_${startLine}`;
|
|
142
|
+
kind = 'hook';
|
|
143
|
+
}
|
|
144
|
+
// Detect IIFE: fn.decl is inside a call_expression (the IIFE invocation)
|
|
145
|
+
const declParent = declCapture.node.parent;
|
|
146
|
+
const isParenWrapped = declParent?.type === 'parenthesized_expression';
|
|
147
|
+
const callParent = isParenWrapped ? declParent.parent : declParent;
|
|
148
|
+
if (callParent?.type === 'call_expression') {
|
|
149
|
+
if (rawName === 'anonymous') {
|
|
150
|
+
rawName = `iife_${declCapture.node.startPosition.row}`;
|
|
151
|
+
}
|
|
152
|
+
kind = 'iife';
|
|
153
|
+
}
|
|
154
|
+
else if (rawName === "anonymous" && !hookNameCapture) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
// Prefix with enclosing scope chain (parent functions, classes, and object literals)
|
|
158
|
+
const scopeChain = (0, extractorUtils_1.getEnclosingScopeChain)(declCapture.node, extractorUtils_1.JS_FN_SCOPE_TYPES, extractorUtils_1.JS_CLASS_SCOPE_TYPES);
|
|
159
|
+
if (scopeChain.length > 0) {
|
|
160
|
+
rawName = `${scopeChain.map(s => s.name).join('.')}.${rawName}`;
|
|
161
|
+
}
|
|
162
|
+
const paramsCapture = match.captures.find((c) => c.name === 'fn.params');
|
|
163
|
+
const isExported = (0, extractorUtils_1.checkExportedByParentWalk)(declCapture.node);
|
|
164
|
+
const paramsList = paramsCapture
|
|
165
|
+
? (0, extractorUtils_1.buildJsParams)(paramsCapture.node, false)
|
|
166
|
+
: (0, extractorUtils_1.getParamsFromFunctionNode)(declCapture.node, false);
|
|
167
|
+
let finalReturnType = null;
|
|
168
|
+
const returnValues = (0, extractorUtils_1.getReturnValues)(declCapture.node, extractorUtils_1.JS_NESTED_FN_TYPES);
|
|
169
|
+
if (returnValues.length > 0) {
|
|
170
|
+
finalReturnType = returnValues.join(' | ');
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
id: `${filePath}::${rawName}::${declCapture.node.startPosition.row}`,
|
|
174
|
+
name: rawName,
|
|
175
|
+
filePath,
|
|
176
|
+
startLine: declCapture.node.startPosition.row,
|
|
177
|
+
endLine: declCapture.node.endPosition.row,
|
|
178
|
+
params: paramsList,
|
|
179
|
+
returnType: finalReturnType,
|
|
180
|
+
isAsync: (0, extractorUtils_1.checkIsAsync)(declCapture.node),
|
|
181
|
+
isExported,
|
|
182
|
+
isEntryPoint: false,
|
|
183
|
+
language: languageId,
|
|
184
|
+
kind,
|
|
185
|
+
...(parentFunctionId ? { parentFunctionId } : {})
|
|
186
|
+
};
|
|
187
|
+
},
|
|
188
|
+
extractCall(match, filePath) {
|
|
189
|
+
const nameCapture = match.captures.find((c) => c.name === 'call.name');
|
|
190
|
+
const exprCapture = match.captures.find((c) => c.name === 'call.expr');
|
|
191
|
+
if (nameCapture && exprCapture) {
|
|
192
|
+
let calleeName = nameCapture.node.text;
|
|
193
|
+
if (nameCapture.node.type === 'member_expression') {
|
|
194
|
+
const prop = nameCapture.node.childForFieldName('property');
|
|
195
|
+
if (prop)
|
|
196
|
+
calleeName = prop.text;
|
|
197
|
+
}
|
|
198
|
+
// Unwrap .bind(): handleWorkerMessage.bind(this) → ref to handleWorkerMessage
|
|
199
|
+
if (calleeName === 'bind' && nameCapture.node.type === 'member_expression') {
|
|
200
|
+
const obj = nameCapture.node.childForFieldName('object');
|
|
201
|
+
if (obj?.type === 'identifier') {
|
|
202
|
+
return {
|
|
203
|
+
callerFilePath: filePath,
|
|
204
|
+
calleeName: obj.text,
|
|
205
|
+
line: exprCapture.node.startPosition.row,
|
|
206
|
+
callType: (0, extractorUtils_1.isInsidePromiseCombinator)(exprCapture.node) ? 'concurrent' : 'ref',
|
|
207
|
+
isRef: true
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const callType = (0, extractorUtils_1.isInsidePromiseCombinator)(exprCapture.node) ? 'concurrent' : undefined;
|
|
212
|
+
const directCall = {
|
|
213
|
+
callerFilePath: filePath,
|
|
214
|
+
calleeName,
|
|
215
|
+
line: exprCapture.node.startPosition.row,
|
|
216
|
+
...(callType ? { callType } : {})
|
|
217
|
+
};
|
|
218
|
+
// Extract function reference arguments from any call
|
|
219
|
+
const refCalls = [];
|
|
220
|
+
const callNode = exprCapture.node;
|
|
221
|
+
const argsNode = callNode.childForFieldName('arguments');
|
|
222
|
+
if (argsNode) {
|
|
223
|
+
for (const arg of argsNode.namedChildren) {
|
|
224
|
+
let refName = null;
|
|
225
|
+
if (arg.type === 'identifier') {
|
|
226
|
+
refName = arg.text;
|
|
227
|
+
}
|
|
228
|
+
else if (arg.type === 'member_expression') {
|
|
229
|
+
const obj = arg.childForFieldName('object');
|
|
230
|
+
const prop = arg.childForFieldName('property');
|
|
231
|
+
if (obj?.type === 'this' && prop) {
|
|
232
|
+
refName = prop.text;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
else if (arg.type === 'call_expression') {
|
|
236
|
+
// Unwrap .bind(): handleWorkerMessage.bind(this) -> handleWorkerMessage
|
|
237
|
+
const fn = arg.childForFieldName('function');
|
|
238
|
+
if (fn?.type === 'member_expression') {
|
|
239
|
+
const prop = fn.childForFieldName('property');
|
|
240
|
+
const obj = fn.childForFieldName('object');
|
|
241
|
+
if (prop?.text === 'bind' && obj?.type === 'identifier') {
|
|
242
|
+
refName = obj.text;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (refName) {
|
|
247
|
+
const refCallType = (0, extractorUtils_1.isInsidePromiseCombinator)(callNode) ? 'concurrent' : 'ref';
|
|
248
|
+
refCalls.push({
|
|
249
|
+
callerFilePath: filePath,
|
|
250
|
+
calleeName: refName,
|
|
251
|
+
line: callNode.startPosition.row,
|
|
252
|
+
callType: refCallType,
|
|
253
|
+
isRef: true
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (refCalls.length > 0) {
|
|
259
|
+
return [directCall, ...refCalls];
|
|
260
|
+
}
|
|
261
|
+
return directCall;
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
};
|