diffninja 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/LICENSE +21 -0
- package/README.md +259 -0
- package/dist/calltree.d.ts +47 -0
- package/dist/calltree.js +296 -0
- package/dist/cli.d.ts +57 -0
- package/dist/cli.js +340 -0
- package/dist/diff.d.ts +7 -0
- package/dist/diff.js +114 -0
- package/dist/extract.d.ts +26 -0
- package/dist/extract.js +152 -0
- package/dist/git.d.ts +40 -0
- package/dist/git.js +288 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +8 -0
- package/dist/infer.d.ts +21 -0
- package/dist/infer.js +189 -0
- package/dist/languages/bash.d.ts +2 -0
- package/dist/languages/bash.js +208 -0
- package/dist/languages/c.d.ts +2 -0
- package/dist/languages/c.js +218 -0
- package/dist/languages/call-syntax.d.ts +125 -0
- package/dist/languages/call-syntax.js +997 -0
- package/dist/languages/cpp.d.ts +2 -0
- package/dist/languages/cpp.js +321 -0
- package/dist/languages/csharp.d.ts +2 -0
- package/dist/languages/csharp.js +324 -0
- package/dist/languages/elixir.d.ts +2 -0
- package/dist/languages/elixir.js +331 -0
- package/dist/languages/go.d.ts +2 -0
- package/dist/languages/go.js +299 -0
- package/dist/languages/grammars.d.ts +50 -0
- package/dist/languages/grammars.js +351 -0
- package/dist/languages/haskell.d.ts +2 -0
- package/dist/languages/haskell.js +250 -0
- package/dist/languages/java.d.ts +2 -0
- package/dist/languages/java.js +351 -0
- package/dist/languages/javascript.d.ts +4 -0
- package/dist/languages/javascript.js +648 -0
- package/dist/languages/kotlin.d.ts +2 -0
- package/dist/languages/kotlin.js +368 -0
- package/dist/languages/lua.d.ts +2 -0
- package/dist/languages/lua.js +212 -0
- package/dist/languages/ocaml.d.ts +2 -0
- package/dist/languages/ocaml.js +291 -0
- package/dist/languages/perl.d.ts +2 -0
- package/dist/languages/perl.js +418 -0
- package/dist/languages/php.d.ts +2 -0
- package/dist/languages/php.js +397 -0
- package/dist/languages/python.d.ts +2 -0
- package/dist/languages/python.js +376 -0
- package/dist/languages/registry.d.ts +7 -0
- package/dist/languages/registry.js +69 -0
- package/dist/languages/ruby.d.ts +2 -0
- package/dist/languages/ruby.js +391 -0
- package/dist/languages/rust.d.ts +2 -0
- package/dist/languages/rust.js +261 -0
- package/dist/languages/scala.d.ts +2 -0
- package/dist/languages/scala.js +307 -0
- package/dist/languages/solidity.d.ts +2 -0
- package/dist/languages/solidity.js +240 -0
- package/dist/languages/swift.d.ts +2 -0
- package/dist/languages/swift.js +268 -0
- package/dist/languages/types.d.ts +36 -0
- package/dist/languages/types.js +74 -0
- package/dist/languages/typescript-contracts.d.ts +57 -0
- package/dist/languages/typescript-contracts.js +528 -0
- package/dist/languages/typescript-dispatch.d.ts +68 -0
- package/dist/languages/typescript-dispatch.js +710 -0
- package/dist/languages/typescript.d.ts +4 -0
- package/dist/languages/typescript.js +722 -0
- package/dist/languages/zig.d.ts +2 -0
- package/dist/languages/zig.js +243 -0
- package/dist/loc.d.ts +17 -0
- package/dist/loc.js +34 -0
- package/dist/reach.d.ts +17 -0
- package/dist/reach.js +65 -0
- package/dist/render.d.ts +18 -0
- package/dist/render.js +83 -0
- package/dist/review/brand.d.ts +8 -0
- package/dist/review/brand.js +25 -0
- package/dist/review/call-context.d.ts +27 -0
- package/dist/review/call-context.js +446 -0
- package/dist/review/call-flow-html.d.ts +32 -0
- package/dist/review/call-flow-html.js +1870 -0
- package/dist/review/call-flow-nav.d.ts +151 -0
- package/dist/review/call-flow-nav.js +317 -0
- package/dist/review/call-flow.d.ts +47 -0
- package/dist/review/call-flow.js +229 -0
- package/dist/review/change-facts.d.ts +69 -0
- package/dist/review/change-facts.js +729 -0
- package/dist/review/cli.d.ts +2 -0
- package/dist/review/cli.js +50 -0
- package/dist/review/connected-analysis.d.ts +100 -0
- package/dist/review/connected-analysis.js +163 -0
- package/dist/review/connected-html.d.ts +17 -0
- package/dist/review/connected-html.js +2853 -0
- package/dist/review/connected.d.ts +23 -0
- package/dist/review/connected.js +141 -0
- package/dist/review/escape-html.d.ts +2 -0
- package/dist/review/escape-html.js +9 -0
- package/dist/review/evidence-html.d.ts +21 -0
- package/dist/review/evidence-html.js +521 -0
- package/dist/review/evidence-syntax.d.ts +132 -0
- package/dist/review/evidence-syntax.js +478 -0
- package/dist/review/evidence-types.d.ts +62 -0
- package/dist/review/evidence-types.js +1 -0
- package/dist/review/evidence.d.ts +31 -0
- package/dist/review/evidence.js +1603 -0
- package/dist/review/file-role.d.ts +9 -0
- package/dist/review/file-role.js +29 -0
- package/dist/review/github.d.ts +204 -0
- package/dist/review/github.js +1245 -0
- package/dist/review/history.d.ts +101 -0
- package/dist/review/history.js +412 -0
- package/dist/review/html.d.ts +34 -0
- package/dist/review/html.js +1104 -0
- package/dist/review/input.d.ts +10 -0
- package/dist/review/input.js +113 -0
- package/dist/review/intent.d.ts +4 -0
- package/dist/review/intent.js +75 -0
- package/dist/review/mcp-cli.d.ts +2 -0
- package/dist/review/mcp-cli.js +25 -0
- package/dist/review/mcp.d.ts +12 -0
- package/dist/review/mcp.js +414 -0
- package/dist/review/module-resolution.d.ts +2 -0
- package/dist/review/module-resolution.js +86 -0
- package/dist/review/palette.d.ts +7 -0
- package/dist/review/palette.js +104 -0
- package/dist/review/pipeline.d.ts +77 -0
- package/dist/review/pipeline.js +227 -0
- package/dist/review/pr-input.d.ts +19 -0
- package/dist/review/pr-input.js +130 -0
- package/dist/review/questions.d.ts +201 -0
- package/dist/review/questions.js +174 -0
- package/dist/review/reference-check.d.ts +7 -0
- package/dist/review/reference-check.js +733 -0
- package/dist/review/report-pages.d.ts +109 -0
- package/dist/review/report-pages.js +328 -0
- package/dist/review/service.d.ts +23 -0
- package/dist/review/service.js +198 -0
- package/dist/review/setup.d.ts +112 -0
- package/dist/review/setup.js +549 -0
- package/dist/review/source.d.ts +26 -0
- package/dist/review/source.js +276 -0
- package/dist/review/toml.d.ts +38 -0
- package/dist/review/toml.js +565 -0
- package/dist/review/types.d.ts +179 -0
- package/dist/review/types.js +1 -0
- package/dist/run.d.ts +49 -0
- package/dist/run.js +311 -0
- package/dist/types.d.ts +366 -0
- package/dist/types.js +83 -0
- package/package.json +88 -0
- package/scripts/ensure-native-grammar.mjs +188 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { childByType, collapseWs, locFromNode, namedChildren, } from "./types.js";
|
|
2
|
+
import { pythonCallSyntax, pythonFunctionScope, pythonModuleScope, pythonParameterList, } from "./call-syntax.js";
|
|
3
|
+
function isLikelyClassName(name) {
|
|
4
|
+
const c = name[0];
|
|
5
|
+
return c !== undefined && c === c.toUpperCase() && c !== c.toLowerCase();
|
|
6
|
+
}
|
|
7
|
+
function isPrivateName(name) {
|
|
8
|
+
return name.startsWith("_") && !name.startsWith("__");
|
|
9
|
+
}
|
|
10
|
+
function getParamsLabel(params) {
|
|
11
|
+
if (!params || params.type !== "parameters")
|
|
12
|
+
return "()";
|
|
13
|
+
const names = [];
|
|
14
|
+
for (const p of namedChildren(params)) {
|
|
15
|
+
if (p.type === "identifier") {
|
|
16
|
+
names.push(p.text);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (p.type === "list_splat_pattern" ||
|
|
20
|
+
p.type === "dictionary_splat_pattern") {
|
|
21
|
+
const id = childByType(p, "identifier");
|
|
22
|
+
const star = p.type === "dictionary_splat_pattern" ? "**" : "*";
|
|
23
|
+
names.push(id ? `${star}${id.text}` : star);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (p.type === "default_parameter" ||
|
|
27
|
+
p.type === "typed_parameter" ||
|
|
28
|
+
p.type === "typed_default_parameter") {
|
|
29
|
+
const id = childByType(p, "identifier");
|
|
30
|
+
names.push(id?.text ?? "_");
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (p.type === "keyword_separator" || p.type === "positional_separator") {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
names.push("_");
|
|
37
|
+
}
|
|
38
|
+
return names.length === 0 ? "()" : `(${names.join(", ")})`;
|
|
39
|
+
}
|
|
40
|
+
function calleeKey(node, className) {
|
|
41
|
+
if (node.type === "identifier") {
|
|
42
|
+
// ClassName() → constructor alias used by __init__ indexing
|
|
43
|
+
if (isLikelyClassName(node.text))
|
|
44
|
+
return `new ${node.text}`;
|
|
45
|
+
return node.text;
|
|
46
|
+
}
|
|
47
|
+
if (node.type === "attribute") {
|
|
48
|
+
const object = node.namedChild(0);
|
|
49
|
+
const attr = node.namedChild(1);
|
|
50
|
+
if (!object || !attr)
|
|
51
|
+
return null;
|
|
52
|
+
const prop = attr.text;
|
|
53
|
+
// super().method() → Class.method (same compromise as TS super.)
|
|
54
|
+
if (object.type === "call" &&
|
|
55
|
+
object.namedChild(0)?.type === "identifier" &&
|
|
56
|
+
object.namedChild(0)?.text === "super" &&
|
|
57
|
+
className) {
|
|
58
|
+
return `${className}.${prop}`;
|
|
59
|
+
}
|
|
60
|
+
if (object.type === "identifier") {
|
|
61
|
+
if ((object.text === "self" || object.text === "cls") && className) {
|
|
62
|
+
return `${className}.${prop}`;
|
|
63
|
+
}
|
|
64
|
+
return `${object.text}.${prop}`;
|
|
65
|
+
}
|
|
66
|
+
if (className)
|
|
67
|
+
return `${className}.${prop}`;
|
|
68
|
+
return prop;
|
|
69
|
+
}
|
|
70
|
+
// obj[key]() — ignore computed
|
|
71
|
+
if (node.type === "subscript")
|
|
72
|
+
return null;
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
function collectBlock(file, block, env) {
|
|
76
|
+
if (!block)
|
|
77
|
+
return [];
|
|
78
|
+
return collectStatements(file, namedChildren(block), env);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Steps of one statement list. `env` carries the lexical scope in effect
|
|
82
|
+
* (module, function, or method), which is what classifies call targets.
|
|
83
|
+
*/
|
|
84
|
+
function collectStatements(file, statements, env) {
|
|
85
|
+
const steps = [];
|
|
86
|
+
const seen = new Set();
|
|
87
|
+
const addCall = (key, node, syntax) => {
|
|
88
|
+
const mark = `${key}:${node.startIndex}`;
|
|
89
|
+
if (seen.has(mark))
|
|
90
|
+
return;
|
|
91
|
+
seen.add(mark);
|
|
92
|
+
const step = { type: "call", key, ...locFromNode(file, node) };
|
|
93
|
+
if (syntax)
|
|
94
|
+
step.syntax = syntax;
|
|
95
|
+
steps.push(step);
|
|
96
|
+
};
|
|
97
|
+
const walk = (node) => {
|
|
98
|
+
// Nested defs / lambdas: do not attribute their bodies to the outer fn
|
|
99
|
+
if (node.type === "function_definition" ||
|
|
100
|
+
node.type === "class_definition" ||
|
|
101
|
+
node.type === "lambda" ||
|
|
102
|
+
node.type === "decorated_definition") {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (node.type === "if_statement") {
|
|
106
|
+
const condNode = namedChildren(node).find((c) => c.type !== "block" &&
|
|
107
|
+
c.type !== "else_clause" &&
|
|
108
|
+
c.type !== "elif_clause") ?? null;
|
|
109
|
+
const cond = condNode ? collapseWs(condNode.text) : "";
|
|
110
|
+
steps.push({
|
|
111
|
+
type: "branch",
|
|
112
|
+
key: cond ? `if:${cond}` : "if",
|
|
113
|
+
label: cond ? `if ${cond}` : "if",
|
|
114
|
+
...locFromNode(file, condNode ?? node),
|
|
115
|
+
children: collectBlock(file, childByType(node, "block"), env),
|
|
116
|
+
});
|
|
117
|
+
for (const clause of namedChildren(node)) {
|
|
118
|
+
if (clause.type === "elif_clause") {
|
|
119
|
+
const elifCond = namedChildren(clause).find((c) => c.type !== "block") ?? null;
|
|
120
|
+
const text = elifCond ? collapseWs(elifCond.text) : "";
|
|
121
|
+
steps.push({
|
|
122
|
+
type: "branch",
|
|
123
|
+
key: text ? `else-if:${text}` : "else-if",
|
|
124
|
+
label: text ? `elif ${text}` : "elif",
|
|
125
|
+
...locFromNode(file, elifCond ?? clause),
|
|
126
|
+
children: collectBlock(file, childByType(clause, "block"), env),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (clause.type === "else_clause") {
|
|
130
|
+
steps.push({
|
|
131
|
+
type: "branch",
|
|
132
|
+
key: "else",
|
|
133
|
+
label: "else",
|
|
134
|
+
...locFromNode(file, clause),
|
|
135
|
+
children: collectBlock(file, childByType(clause, "block"), env),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (node.type === "match_statement") {
|
|
142
|
+
const subject = namedChildren(node).find((c) => c.type !== "block") ?? null;
|
|
143
|
+
const subjectText = subject ? collapseWs(subject.text) : "";
|
|
144
|
+
const block = childByType(node, "block");
|
|
145
|
+
for (const clause of block ? namedChildren(block) : []) {
|
|
146
|
+
if (clause.type !== "case_clause")
|
|
147
|
+
continue;
|
|
148
|
+
const pattern = namedChildren(clause).find((c) => c.type !== "block") ?? null;
|
|
149
|
+
const text = pattern ? collapseWs(pattern.text) : "";
|
|
150
|
+
const label = text
|
|
151
|
+
? `case ${text}`
|
|
152
|
+
: subjectText
|
|
153
|
+
? `case ${subjectText}`
|
|
154
|
+
: "case";
|
|
155
|
+
steps.push({
|
|
156
|
+
type: "branch",
|
|
157
|
+
key: text ? `case:${text}` : "case",
|
|
158
|
+
label,
|
|
159
|
+
...locFromNode(file, pattern ?? clause),
|
|
160
|
+
children: collectBlock(file, childByType(clause, "block"), env),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (node.type === "try_statement") {
|
|
166
|
+
const tryBlock = childByType(node, "block");
|
|
167
|
+
steps.push({
|
|
168
|
+
type: "branch",
|
|
169
|
+
key: "try",
|
|
170
|
+
label: "try",
|
|
171
|
+
...locFromNode(file, node),
|
|
172
|
+
children: collectBlock(file, tryBlock, env),
|
|
173
|
+
});
|
|
174
|
+
for (const clause of namedChildren(node)) {
|
|
175
|
+
if (clause.type === "except_clause") {
|
|
176
|
+
const handlerType = namedChildren(clause).find((c) => c.type !== "block" && c.type !== "as_pattern") ?? null;
|
|
177
|
+
const text = handlerType ? collapseWs(handlerType.text) : "";
|
|
178
|
+
steps.push({
|
|
179
|
+
type: "branch",
|
|
180
|
+
key: text ? `except:${text}` : "except",
|
|
181
|
+
label: text ? `except ${text}` : "except",
|
|
182
|
+
...locFromNode(file, handlerType ?? clause),
|
|
183
|
+
children: collectBlock(file, childByType(clause, "block"), env),
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
if (clause.type === "else_clause") {
|
|
187
|
+
steps.push({
|
|
188
|
+
type: "branch",
|
|
189
|
+
key: "else",
|
|
190
|
+
label: "else",
|
|
191
|
+
...locFromNode(file, clause),
|
|
192
|
+
children: collectBlock(file, childByType(clause, "block"), env),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (clause.type === "finally_clause") {
|
|
196
|
+
steps.push({
|
|
197
|
+
type: "branch",
|
|
198
|
+
key: "finally",
|
|
199
|
+
label: "finally",
|
|
200
|
+
...locFromNode(file, clause),
|
|
201
|
+
children: collectBlock(file, childByType(clause, "block"), env),
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (node.type === "call") {
|
|
208
|
+
const callee = node.namedChild(0);
|
|
209
|
+
if (callee) {
|
|
210
|
+
const args = childByType(node, "argument_list");
|
|
211
|
+
const syntax = pythonCallSyntax(callee, args, env);
|
|
212
|
+
// A dynamic target has no key from `calleeKey`; the call is still a
|
|
213
|
+
// call, so the target expression itself becomes its identity.
|
|
214
|
+
addCall(calleeKey(callee, env.className) ?? syntax?.callee ?? "", node, syntax);
|
|
215
|
+
}
|
|
216
|
+
// Still walk arguments for nested calls, but not into nested lambdas
|
|
217
|
+
for (const child of namedChildren(node).slice(1))
|
|
218
|
+
walk(child);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
for (const child of namedChildren(node))
|
|
222
|
+
walk(child);
|
|
223
|
+
};
|
|
224
|
+
for (const stmt of statements)
|
|
225
|
+
walk(stmt);
|
|
226
|
+
return steps;
|
|
227
|
+
}
|
|
228
|
+
function pushFunction(file, node, name, exported, outer, params, body, functions) {
|
|
229
|
+
const className = outer.className;
|
|
230
|
+
const isInit = className !== null && name === "__init__";
|
|
231
|
+
const key = className
|
|
232
|
+
? isInit
|
|
233
|
+
? `${className}.__init__`
|
|
234
|
+
: `${className}.${name}`
|
|
235
|
+
: name;
|
|
236
|
+
const label = isInit ? `${className}()` : key;
|
|
237
|
+
// The body's scope chains to the enclosing one; its own params and locals
|
|
238
|
+
// shadow outer names.
|
|
239
|
+
const env = {
|
|
240
|
+
scope: pythonFunctionScope(node, outer.scope),
|
|
241
|
+
className,
|
|
242
|
+
};
|
|
243
|
+
const declared = pythonParameterList(params);
|
|
244
|
+
const info = {
|
|
245
|
+
key,
|
|
246
|
+
label: `${label}${getParamsLabel(params)}`,
|
|
247
|
+
file,
|
|
248
|
+
steps: body && body.type === "block"
|
|
249
|
+
? collectBlock(file, body, env)
|
|
250
|
+
: body
|
|
251
|
+
? collectStatements(file, [body], env)
|
|
252
|
+
: [],
|
|
253
|
+
exported,
|
|
254
|
+
start: node.startIndex,
|
|
255
|
+
end: node.endIndex,
|
|
256
|
+
};
|
|
257
|
+
if (declared)
|
|
258
|
+
info.params = declared;
|
|
259
|
+
functions.push(info);
|
|
260
|
+
if (isInit && className) {
|
|
261
|
+
functions.push({
|
|
262
|
+
...info,
|
|
263
|
+
key: `new ${className}`,
|
|
264
|
+
label: `${className}()`,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function handleFunctionDefinition(file, node, exported, outer, functions) {
|
|
269
|
+
const name = childByType(node, "identifier")?.text ?? null;
|
|
270
|
+
if (!name)
|
|
271
|
+
return;
|
|
272
|
+
// Skip most dunders; keep __init__ and __call__
|
|
273
|
+
if (name.startsWith("__") &&
|
|
274
|
+
name.endsWith("__") &&
|
|
275
|
+
name !== "__init__" &&
|
|
276
|
+
name !== "__call__") {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const params = childByType(node, "parameters");
|
|
280
|
+
const body = childByType(node, "block");
|
|
281
|
+
const methodExported = exported && !isPrivateName(name);
|
|
282
|
+
pushFunction(file, node, name, methodExported, outer, params, body, functions);
|
|
283
|
+
}
|
|
284
|
+
function handleLambdaAssignment(file, assignment, exported, outer, functions) {
|
|
285
|
+
const id = childByType(assignment, "identifier");
|
|
286
|
+
const lambda = childByType(assignment, "lambda");
|
|
287
|
+
if (!id || !lambda)
|
|
288
|
+
return;
|
|
289
|
+
const params = childByType(lambda, "lambda_parameters");
|
|
290
|
+
// lambda body is last named child that isn't params
|
|
291
|
+
const body = namedChildren(lambda).find((c) => c.type !== "lambda_parameters") ?? null;
|
|
292
|
+
pushFunction(file, lambda, id.text, exported && !isPrivateName(id.text), outer, params, body, functions);
|
|
293
|
+
}
|
|
294
|
+
function handleClass(file, node, exported, functions, outer) {
|
|
295
|
+
const className = childByType(node, "identifier")?.text ?? null;
|
|
296
|
+
if (!className)
|
|
297
|
+
return;
|
|
298
|
+
const body = childByType(node, "block");
|
|
299
|
+
if (!body)
|
|
300
|
+
return;
|
|
301
|
+
// Methods resolve `self.name()`; the class body itself sees the outer scope.
|
|
302
|
+
const classEnv = {
|
|
303
|
+
scope: outer.scope,
|
|
304
|
+
className,
|
|
305
|
+
};
|
|
306
|
+
for (const stmt of namedChildren(body)) {
|
|
307
|
+
if (stmt.type === "decorated_definition") {
|
|
308
|
+
const fn = childByType(stmt, "function_definition");
|
|
309
|
+
if (fn) {
|
|
310
|
+
// @property methods are still indexed (like TS getters)
|
|
311
|
+
handleFunctionDefinition(file, fn, exported && !isPrivateName(className), classEnv, functions);
|
|
312
|
+
}
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
if (stmt.type === "function_definition") {
|
|
316
|
+
handleFunctionDefinition(file, stmt, exported && !isPrivateName(className), classEnv, functions);
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (stmt.type === "expression_statement") {
|
|
320
|
+
const assignment = childByType(stmt, "assignment");
|
|
321
|
+
if (assignment) {
|
|
322
|
+
handleLambdaAssignment(file, assignment, exported && !isPrivateName(className), classEnv, functions);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function visitModule(file, node, functions, env) {
|
|
328
|
+
if (node.type === "decorated_definition") {
|
|
329
|
+
const inner = childByType(node, "function_definition") ??
|
|
330
|
+
childByType(node, "class_definition");
|
|
331
|
+
if (inner?.type === "function_definition") {
|
|
332
|
+
const name = childByType(inner, "identifier")?.text ?? "";
|
|
333
|
+
handleFunctionDefinition(file, inner, !isPrivateName(name), env, functions);
|
|
334
|
+
}
|
|
335
|
+
else if (inner?.type === "class_definition") {
|
|
336
|
+
const name = childByType(inner, "identifier")?.text ?? "";
|
|
337
|
+
handleClass(file, inner, !isPrivateName(name), functions, env);
|
|
338
|
+
}
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (node.type === "function_definition") {
|
|
342
|
+
const name = childByType(node, "identifier")?.text ?? "";
|
|
343
|
+
handleFunctionDefinition(file, node, !isPrivateName(name), env, functions);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (node.type === "class_definition") {
|
|
347
|
+
const name = childByType(node, "identifier")?.text ?? "";
|
|
348
|
+
handleClass(file, node, !isPrivateName(name), functions, env);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (node.type === "expression_statement") {
|
|
352
|
+
const assignment = childByType(node, "assignment");
|
|
353
|
+
if (assignment) {
|
|
354
|
+
const id = childByType(assignment, "identifier");
|
|
355
|
+
handleLambdaAssignment(file, assignment, id ? !isPrivateName(id.text) : true, env, functions);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function extractFromTree(file, _source, tree) {
|
|
360
|
+
const functions = [];
|
|
361
|
+
const root = tree.rootNode;
|
|
362
|
+
const env = {
|
|
363
|
+
scope: pythonModuleScope(root),
|
|
364
|
+
className: null,
|
|
365
|
+
};
|
|
366
|
+
for (const stmt of namedChildren(root)) {
|
|
367
|
+
visitModule(file, stmt, functions, env);
|
|
368
|
+
}
|
|
369
|
+
return functions;
|
|
370
|
+
}
|
|
371
|
+
export const pythonExtractor = {
|
|
372
|
+
id: "python",
|
|
373
|
+
extensions: [".py"],
|
|
374
|
+
grammarPackage: "tree-sitter-python",
|
|
375
|
+
extract: extractFromTree,
|
|
376
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LanguageExtractor } from "./types.js";
|
|
2
|
+
declare const extractors: LanguageExtractor[];
|
|
3
|
+
export declare function listSupportedExtensions(): string[];
|
|
4
|
+
export declare function listSupportedLanguages(): string[];
|
|
5
|
+
export declare function detectLanguage(file: string): LanguageExtractor | null;
|
|
6
|
+
export declare function getExtractor(id: string): LanguageExtractor | null;
|
|
7
|
+
export { extractors };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { extname } from "node:path";
|
|
2
|
+
import { bashExtractor } from "./bash.js";
|
|
3
|
+
import { cExtractor } from "./c.js";
|
|
4
|
+
import { cppExtractor } from "./cpp.js";
|
|
5
|
+
import { csharpExtractor } from "./csharp.js";
|
|
6
|
+
import { elixirExtractor } from "./elixir.js";
|
|
7
|
+
import { goExtractor } from "./go.js";
|
|
8
|
+
import { haskellExtractor } from "./haskell.js";
|
|
9
|
+
import { javaExtractor } from "./java.js";
|
|
10
|
+
import { javascriptExtractor, javascriptreactExtractor } from "./javascript.js";
|
|
11
|
+
import { kotlinExtractor } from "./kotlin.js";
|
|
12
|
+
import { luaExtractor } from "./lua.js";
|
|
13
|
+
import { ocamlExtractor } from "./ocaml.js";
|
|
14
|
+
import { perlExtractor } from "./perl.js";
|
|
15
|
+
import { phpExtractor } from "./php.js";
|
|
16
|
+
import { pythonExtractor } from "./python.js";
|
|
17
|
+
import { rubyExtractor } from "./ruby.js";
|
|
18
|
+
import { rustExtractor } from "./rust.js";
|
|
19
|
+
import { scalaExtractor } from "./scala.js";
|
|
20
|
+
import { solidityExtractor } from "./solidity.js";
|
|
21
|
+
import { swiftExtractor } from "./swift.js";
|
|
22
|
+
import { typescriptExtractor, typescriptreactExtractor, } from "./typescript.js";
|
|
23
|
+
import { zigExtractor } from "./zig.js";
|
|
24
|
+
const extractors = [
|
|
25
|
+
typescriptExtractor,
|
|
26
|
+
typescriptreactExtractor,
|
|
27
|
+
javascriptExtractor,
|
|
28
|
+
javascriptreactExtractor,
|
|
29
|
+
pythonExtractor,
|
|
30
|
+
goExtractor,
|
|
31
|
+
rustExtractor,
|
|
32
|
+
javaExtractor,
|
|
33
|
+
rubyExtractor,
|
|
34
|
+
cExtractor,
|
|
35
|
+
cppExtractor,
|
|
36
|
+
csharpExtractor,
|
|
37
|
+
phpExtractor,
|
|
38
|
+
kotlinExtractor,
|
|
39
|
+
swiftExtractor,
|
|
40
|
+
scalaExtractor,
|
|
41
|
+
luaExtractor,
|
|
42
|
+
elixirExtractor,
|
|
43
|
+
bashExtractor,
|
|
44
|
+
haskellExtractor,
|
|
45
|
+
zigExtractor,
|
|
46
|
+
solidityExtractor,
|
|
47
|
+
ocamlExtractor,
|
|
48
|
+
perlExtractor,
|
|
49
|
+
];
|
|
50
|
+
const byExtension = new Map();
|
|
51
|
+
for (const extractor of extractors) {
|
|
52
|
+
for (const ext of extractor.extensions) {
|
|
53
|
+
byExtension.set(ext.toLowerCase(), extractor);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function listSupportedExtensions() {
|
|
57
|
+
return [...byExtension.keys()].sort();
|
|
58
|
+
}
|
|
59
|
+
export function listSupportedLanguages() {
|
|
60
|
+
return extractors.map((e) => e.id);
|
|
61
|
+
}
|
|
62
|
+
export function detectLanguage(file) {
|
|
63
|
+
const ext = extname(file).toLowerCase();
|
|
64
|
+
return byExtension.get(ext) ?? null;
|
|
65
|
+
}
|
|
66
|
+
export function getExtractor(id) {
|
|
67
|
+
return extractors.find((e) => e.id === id) ?? null;
|
|
68
|
+
}
|
|
69
|
+
export { extractors };
|