@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.
@@ -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,2 @@
1
+ import { LanguageAnalyzer } from '../../types';
2
+ export declare const javascriptAnalyzer: LanguageAnalyzer;
@@ -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
+ };
@@ -0,0 +1,2 @@
1
+ import { LanguageAnalyzer } from '../../types';
2
+ export declare const jsxAnalyzer: LanguageAnalyzer;