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.
Files changed (154) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +259 -0
  3. package/dist/calltree.d.ts +47 -0
  4. package/dist/calltree.js +296 -0
  5. package/dist/cli.d.ts +57 -0
  6. package/dist/cli.js +340 -0
  7. package/dist/diff.d.ts +7 -0
  8. package/dist/diff.js +114 -0
  9. package/dist/extract.d.ts +26 -0
  10. package/dist/extract.js +152 -0
  11. package/dist/git.d.ts +40 -0
  12. package/dist/git.js +288 -0
  13. package/dist/index.d.ts +9 -0
  14. package/dist/index.js +8 -0
  15. package/dist/infer.d.ts +21 -0
  16. package/dist/infer.js +189 -0
  17. package/dist/languages/bash.d.ts +2 -0
  18. package/dist/languages/bash.js +208 -0
  19. package/dist/languages/c.d.ts +2 -0
  20. package/dist/languages/c.js +218 -0
  21. package/dist/languages/call-syntax.d.ts +125 -0
  22. package/dist/languages/call-syntax.js +997 -0
  23. package/dist/languages/cpp.d.ts +2 -0
  24. package/dist/languages/cpp.js +321 -0
  25. package/dist/languages/csharp.d.ts +2 -0
  26. package/dist/languages/csharp.js +324 -0
  27. package/dist/languages/elixir.d.ts +2 -0
  28. package/dist/languages/elixir.js +331 -0
  29. package/dist/languages/go.d.ts +2 -0
  30. package/dist/languages/go.js +299 -0
  31. package/dist/languages/grammars.d.ts +50 -0
  32. package/dist/languages/grammars.js +351 -0
  33. package/dist/languages/haskell.d.ts +2 -0
  34. package/dist/languages/haskell.js +250 -0
  35. package/dist/languages/java.d.ts +2 -0
  36. package/dist/languages/java.js +351 -0
  37. package/dist/languages/javascript.d.ts +4 -0
  38. package/dist/languages/javascript.js +648 -0
  39. package/dist/languages/kotlin.d.ts +2 -0
  40. package/dist/languages/kotlin.js +368 -0
  41. package/dist/languages/lua.d.ts +2 -0
  42. package/dist/languages/lua.js +212 -0
  43. package/dist/languages/ocaml.d.ts +2 -0
  44. package/dist/languages/ocaml.js +291 -0
  45. package/dist/languages/perl.d.ts +2 -0
  46. package/dist/languages/perl.js +418 -0
  47. package/dist/languages/php.d.ts +2 -0
  48. package/dist/languages/php.js +397 -0
  49. package/dist/languages/python.d.ts +2 -0
  50. package/dist/languages/python.js +376 -0
  51. package/dist/languages/registry.d.ts +7 -0
  52. package/dist/languages/registry.js +69 -0
  53. package/dist/languages/ruby.d.ts +2 -0
  54. package/dist/languages/ruby.js +391 -0
  55. package/dist/languages/rust.d.ts +2 -0
  56. package/dist/languages/rust.js +261 -0
  57. package/dist/languages/scala.d.ts +2 -0
  58. package/dist/languages/scala.js +307 -0
  59. package/dist/languages/solidity.d.ts +2 -0
  60. package/dist/languages/solidity.js +240 -0
  61. package/dist/languages/swift.d.ts +2 -0
  62. package/dist/languages/swift.js +268 -0
  63. package/dist/languages/types.d.ts +36 -0
  64. package/dist/languages/types.js +74 -0
  65. package/dist/languages/typescript-contracts.d.ts +57 -0
  66. package/dist/languages/typescript-contracts.js +528 -0
  67. package/dist/languages/typescript-dispatch.d.ts +68 -0
  68. package/dist/languages/typescript-dispatch.js +710 -0
  69. package/dist/languages/typescript.d.ts +4 -0
  70. package/dist/languages/typescript.js +722 -0
  71. package/dist/languages/zig.d.ts +2 -0
  72. package/dist/languages/zig.js +243 -0
  73. package/dist/loc.d.ts +17 -0
  74. package/dist/loc.js +34 -0
  75. package/dist/reach.d.ts +17 -0
  76. package/dist/reach.js +65 -0
  77. package/dist/render.d.ts +18 -0
  78. package/dist/render.js +83 -0
  79. package/dist/review/brand.d.ts +8 -0
  80. package/dist/review/brand.js +25 -0
  81. package/dist/review/call-context.d.ts +27 -0
  82. package/dist/review/call-context.js +446 -0
  83. package/dist/review/call-flow-html.d.ts +32 -0
  84. package/dist/review/call-flow-html.js +1870 -0
  85. package/dist/review/call-flow-nav.d.ts +151 -0
  86. package/dist/review/call-flow-nav.js +317 -0
  87. package/dist/review/call-flow.d.ts +47 -0
  88. package/dist/review/call-flow.js +229 -0
  89. package/dist/review/change-facts.d.ts +69 -0
  90. package/dist/review/change-facts.js +729 -0
  91. package/dist/review/cli.d.ts +2 -0
  92. package/dist/review/cli.js +50 -0
  93. package/dist/review/connected-analysis.d.ts +100 -0
  94. package/dist/review/connected-analysis.js +163 -0
  95. package/dist/review/connected-html.d.ts +17 -0
  96. package/dist/review/connected-html.js +2853 -0
  97. package/dist/review/connected.d.ts +23 -0
  98. package/dist/review/connected.js +141 -0
  99. package/dist/review/escape-html.d.ts +2 -0
  100. package/dist/review/escape-html.js +9 -0
  101. package/dist/review/evidence-html.d.ts +21 -0
  102. package/dist/review/evidence-html.js +521 -0
  103. package/dist/review/evidence-syntax.d.ts +132 -0
  104. package/dist/review/evidence-syntax.js +478 -0
  105. package/dist/review/evidence-types.d.ts +62 -0
  106. package/dist/review/evidence-types.js +1 -0
  107. package/dist/review/evidence.d.ts +31 -0
  108. package/dist/review/evidence.js +1603 -0
  109. package/dist/review/file-role.d.ts +9 -0
  110. package/dist/review/file-role.js +29 -0
  111. package/dist/review/github.d.ts +204 -0
  112. package/dist/review/github.js +1245 -0
  113. package/dist/review/history.d.ts +101 -0
  114. package/dist/review/history.js +412 -0
  115. package/dist/review/html.d.ts +34 -0
  116. package/dist/review/html.js +1104 -0
  117. package/dist/review/input.d.ts +10 -0
  118. package/dist/review/input.js +113 -0
  119. package/dist/review/intent.d.ts +4 -0
  120. package/dist/review/intent.js +75 -0
  121. package/dist/review/mcp-cli.d.ts +2 -0
  122. package/dist/review/mcp-cli.js +25 -0
  123. package/dist/review/mcp.d.ts +12 -0
  124. package/dist/review/mcp.js +414 -0
  125. package/dist/review/module-resolution.d.ts +2 -0
  126. package/dist/review/module-resolution.js +86 -0
  127. package/dist/review/palette.d.ts +7 -0
  128. package/dist/review/palette.js +104 -0
  129. package/dist/review/pipeline.d.ts +77 -0
  130. package/dist/review/pipeline.js +227 -0
  131. package/dist/review/pr-input.d.ts +19 -0
  132. package/dist/review/pr-input.js +130 -0
  133. package/dist/review/questions.d.ts +201 -0
  134. package/dist/review/questions.js +174 -0
  135. package/dist/review/reference-check.d.ts +7 -0
  136. package/dist/review/reference-check.js +733 -0
  137. package/dist/review/report-pages.d.ts +109 -0
  138. package/dist/review/report-pages.js +328 -0
  139. package/dist/review/service.d.ts +23 -0
  140. package/dist/review/service.js +198 -0
  141. package/dist/review/setup.d.ts +112 -0
  142. package/dist/review/setup.js +549 -0
  143. package/dist/review/source.d.ts +26 -0
  144. package/dist/review/source.js +276 -0
  145. package/dist/review/toml.d.ts +38 -0
  146. package/dist/review/toml.js +565 -0
  147. package/dist/review/types.d.ts +179 -0
  148. package/dist/review/types.js +1 -0
  149. package/dist/run.d.ts +49 -0
  150. package/dist/run.js +311 -0
  151. package/dist/types.d.ts +366 -0
  152. package/dist/types.js +83 -0
  153. package/package.json +88 -0
  154. 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 };
@@ -0,0 +1,2 @@
1
+ import { type LanguageExtractor } from "./types.js";
2
+ export declare const rubyExtractor: LanguageExtractor;