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,397 @@
1
+ import { heuristicCallSyntax } from "./call-syntax.js";
2
+ import { childByType, declaredParamsOf, collapseWs, locFromNode, namedChildren, sameNode, } from "./types.js";
3
+ function isPrivate(node) {
4
+ return namedChildren(node).some((c) => c.type === "visibility_modifier" && c.text === "private");
5
+ }
6
+ function nameText(node) {
7
+ if (!node)
8
+ return null;
9
+ if (node.type === "name")
10
+ return node.text;
11
+ if (node.type === "variable_name") {
12
+ return childByType(node, "name")?.text ?? node.text.replace(/^\$/, "");
13
+ }
14
+ if (node.type === "qualified_name") {
15
+ return collapseWs(node.text).replace(/^\s*\\/, "");
16
+ }
17
+ return node.text;
18
+ }
19
+ function getParamsLabel(params) {
20
+ if (!params || params.type !== "formal_parameters")
21
+ return "()";
22
+ const names = [];
23
+ for (const p of namedChildren(params)) {
24
+ if (p.type !== "simple_parameter" && p.type !== "variadic_parameter") {
25
+ continue;
26
+ }
27
+ const varName = childByType(p, "variable_name");
28
+ const n = nameText(varName);
29
+ if (p.type === "variadic_parameter") {
30
+ names.push(n ? `...${n}` : "...");
31
+ }
32
+ else {
33
+ names.push(n ?? "_");
34
+ }
35
+ }
36
+ return names.length === 0 ? "()" : `(${names.join(", ")})`;
37
+ }
38
+ function calleeKey(node) {
39
+ // Bare / qualified function call callee is usually `name` or `qualified_name`
40
+ if (node.type === "name")
41
+ return node.text;
42
+ if (node.type === "qualified_name") {
43
+ return collapseWs(node.text).replace(/^\s*\\/, "");
44
+ }
45
+ if (node.type === "variable_name") {
46
+ // Dynamic $fn() — ignore
47
+ return null;
48
+ }
49
+ return null;
50
+ }
51
+ function memberCallKey(node, className) {
52
+ // $this->prepare() / $obj->method()
53
+ const object = node.namedChild(0);
54
+ const method = namedChildren(node).find((c) => c.type === "name") ?? null;
55
+ if (!object || !method)
56
+ return null;
57
+ const prop = method.text;
58
+ const objName = nameText(object);
59
+ if (objName === "this" && className) {
60
+ return `${className}.${prop}`;
61
+ }
62
+ if (objName)
63
+ return `${objName}.${prop}`;
64
+ if (className)
65
+ return `${className}.${prop}`;
66
+ return prop;
67
+ }
68
+ function condText(node) {
69
+ if (!node)
70
+ return "";
71
+ if (node.type === "parenthesized_expression") {
72
+ const inner = node.namedChild(0);
73
+ if (inner)
74
+ return collapseWs(inner.text);
75
+ }
76
+ return collapseWs(node.text);
77
+ }
78
+ function collectStatements(file, statements, className) {
79
+ const steps = [];
80
+ const seen = new Set();
81
+ const addCall = (key, node) => {
82
+ const mark = `${key}:${node.startIndex}`;
83
+ if (seen.has(mark))
84
+ return;
85
+ seen.add(mark);
86
+ const step = { type: "call", key, ...locFromNode(file, node) };
87
+ step.syntax = heuristicCallSyntax(node, key);
88
+ steps.push(step);
89
+ };
90
+ const walk = (node) => {
91
+ if (node.type === "function_definition" ||
92
+ node.type === "method_declaration" ||
93
+ node.type === "anonymous_function" ||
94
+ node.type === "arrow_function" ||
95
+ node.type === "class_declaration") {
96
+ return;
97
+ }
98
+ if (node.type === "if_statement") {
99
+ const cond = node.childForFieldName("condition") ??
100
+ childByType(node, "parenthesized_expression");
101
+ const consequent = node.childForFieldName("body") ??
102
+ node.childForFieldName("consequence") ??
103
+ namedChildren(node).find((c) => c.type !== "parenthesized_expression" &&
104
+ c.type !== "else_clause" &&
105
+ c.type !== "else_if_clause") ??
106
+ null;
107
+ const text = condText(cond);
108
+ steps.push({
109
+ type: "branch",
110
+ key: text ? `if:${text}` : "if",
111
+ label: text ? `if ${text}` : "if",
112
+ ...locFromNode(file, cond ?? node),
113
+ children: consequent
114
+ ? collectStatements(file, consequent.type === "compound_statement"
115
+ ? namedChildren(consequent)
116
+ : [consequent], className)
117
+ : [],
118
+ });
119
+ for (const child of namedChildren(node)) {
120
+ if (child.type === "else_if_clause") {
121
+ const elifCond = child.childForFieldName("condition") ??
122
+ childByType(child, "parenthesized_expression");
123
+ const elifText = condText(elifCond);
124
+ const elifCons = child.childForFieldName("body") ??
125
+ namedChildren(child).find((c) => c.type !== "parenthesized_expression") ??
126
+ null;
127
+ steps.push({
128
+ type: "branch",
129
+ key: elifText ? `else-if:${elifText}` : "else-if",
130
+ label: elifText ? `elseif ${elifText}` : "elseif",
131
+ ...locFromNode(file, elifCond ?? child),
132
+ children: elifCons
133
+ ? collectStatements(file, elifCons.type === "compound_statement"
134
+ ? namedChildren(elifCons)
135
+ : [elifCons], className)
136
+ : [],
137
+ });
138
+ continue;
139
+ }
140
+ if (child.type !== "else_clause")
141
+ continue;
142
+ let elseClause = child;
143
+ while (elseClause) {
144
+ const inner = childByType(elseClause, "if_statement") ??
145
+ elseClause.namedChild(0);
146
+ if (!inner)
147
+ break;
148
+ if (inner.type === "if_statement") {
149
+ const elifCond = inner.childForFieldName("condition") ??
150
+ childByType(inner, "parenthesized_expression");
151
+ const elifText = condText(elifCond);
152
+ const elifCons = inner.childForFieldName("body") ??
153
+ inner.childForFieldName("consequence") ??
154
+ namedChildren(inner).find((c) => c.type !== "parenthesized_expression" &&
155
+ c.type !== "else_clause" &&
156
+ c.type !== "else_if_clause") ??
157
+ null;
158
+ steps.push({
159
+ type: "branch",
160
+ key: elifText ? `else-if:${elifText}` : "else-if",
161
+ label: elifText ? `elseif ${elifText}` : "elseif",
162
+ ...locFromNode(file, elifCond ?? elseClause),
163
+ children: elifCons
164
+ ? collectStatements(file, elifCons.type === "compound_statement"
165
+ ? namedChildren(elifCons)
166
+ : [elifCons], className)
167
+ : [],
168
+ });
169
+ // Nested if may have else_if_clause siblings too
170
+ for (const nested of namedChildren(inner)) {
171
+ if (nested.type === "else_if_clause") {
172
+ const nCond = nested.childForFieldName("condition") ??
173
+ childByType(nested, "parenthesized_expression");
174
+ const nText = condText(nCond);
175
+ const nBody = nested.childForFieldName("body") ??
176
+ namedChildren(nested).find((c) => c.type !== "parenthesized_expression") ??
177
+ null;
178
+ steps.push({
179
+ type: "branch",
180
+ key: nText ? `else-if:${nText}` : "else-if",
181
+ label: nText ? `elseif ${nText}` : "elseif",
182
+ ...locFromNode(file, nCond ?? nested),
183
+ children: nBody
184
+ ? collectStatements(file, nBody.type === "compound_statement"
185
+ ? namedChildren(nBody)
186
+ : [nBody], className)
187
+ : [],
188
+ });
189
+ }
190
+ }
191
+ elseClause = childByType(inner, "else_clause");
192
+ continue;
193
+ }
194
+ steps.push({
195
+ type: "branch",
196
+ key: "else",
197
+ label: "else",
198
+ ...locFromNode(file, elseClause),
199
+ children: collectStatements(file, inner.type === "compound_statement"
200
+ ? namedChildren(inner)
201
+ : [inner], className),
202
+ });
203
+ break;
204
+ }
205
+ }
206
+ return;
207
+ }
208
+ if (node.type === "try_statement") {
209
+ const body = node.childForFieldName("body") ??
210
+ childByType(node, "compound_statement");
211
+ steps.push({
212
+ type: "branch",
213
+ key: "try",
214
+ label: "try",
215
+ ...locFromNode(file, node),
216
+ children: body
217
+ ? collectStatements(file, namedChildren(body), className)
218
+ : [],
219
+ });
220
+ for (const clause of namedChildren(node)) {
221
+ if (clause.type === "catch_clause") {
222
+ const types = childByType(clause, "type_list") ??
223
+ namedChildren(clause).find((c) => c.type === "type_list") ??
224
+ null;
225
+ const text = types ? collapseWs(types.text) : "";
226
+ const catchBody = clause.childForFieldName("body") ??
227
+ childByType(clause, "compound_statement");
228
+ steps.push({
229
+ type: "branch",
230
+ key: text ? `catch:${text}` : "catch",
231
+ label: text ? `catch ${text}` : "catch",
232
+ ...locFromNode(file, types ?? clause),
233
+ children: catchBody
234
+ ? collectStatements(file, namedChildren(catchBody), className)
235
+ : [],
236
+ });
237
+ }
238
+ if (clause.type === "finally_clause") {
239
+ const finallyBody = clause.childForFieldName("body") ??
240
+ childByType(clause, "compound_statement");
241
+ steps.push({
242
+ type: "branch",
243
+ key: "finally",
244
+ label: "finally",
245
+ ...locFromNode(file, clause),
246
+ children: finallyBody
247
+ ? collectStatements(file, namedChildren(finallyBody), className)
248
+ : [],
249
+ });
250
+ }
251
+ }
252
+ return;
253
+ }
254
+ if (node.type === "function_call_expression") {
255
+ const callee = node.namedChild(0);
256
+ if (callee) {
257
+ const key = calleeKey(callee);
258
+ if (key)
259
+ addCall(key, node);
260
+ }
261
+ }
262
+ else if (node.type === "member_call_expression") {
263
+ const key = memberCallKey(node, className);
264
+ if (key)
265
+ addCall(key, node);
266
+ }
267
+ else if (node.type === "scoped_call_expression") {
268
+ // Foo::bar() / self::bar() / static::bar() / parent::bar()
269
+ const method = namedChildren(node).filter((c) => c.type === "name").at(-1) ?? null;
270
+ if (!method) {
271
+ // fall through to children
272
+ }
273
+ else {
274
+ const scope = childByType(node, "relative_scope") ??
275
+ namedChildren(node).find((c) => c.type === "name" && !sameNode(c, method)) ??
276
+ null;
277
+ const scopeText = scope?.text ?? null;
278
+ if (scopeText === "self" ||
279
+ scopeText === "static" ||
280
+ scopeText === "parent") {
281
+ addCall(className ? `${className}.${method.text}` : method.text, node);
282
+ }
283
+ else if (scopeText) {
284
+ addCall(`${scopeText}.${method.text}`, node);
285
+ }
286
+ else {
287
+ addCall(method.text, node);
288
+ }
289
+ }
290
+ }
291
+ else if (node.type === "object_creation_expression") {
292
+ const typeName = namedChildren(node).find((c) => c.type === "name" || c.type === "qualified_name") ?? null;
293
+ if (typeName) {
294
+ const n = nameText(typeName);
295
+ if (n)
296
+ addCall(`new ${n}`, node);
297
+ }
298
+ }
299
+ for (const child of namedChildren(node))
300
+ walk(child);
301
+ };
302
+ for (const stmt of statements)
303
+ walk(stmt);
304
+ return steps;
305
+ }
306
+ function handleFunction(file, node, functions) {
307
+ const name = childByType(node, "name")?.text ?? null;
308
+ if (!name)
309
+ return;
310
+ const params = childByType(node, "formal_parameters");
311
+ const body = childByType(node, "compound_statement");
312
+ functions.push({
313
+ key: name,
314
+ label: `${name}${getParamsLabel(params)}`,
315
+ params: declaredParamsOf(node),
316
+ file,
317
+ steps: body ? collectStatements(file, namedChildren(body), null) : [],
318
+ exported: true,
319
+ start: node.startIndex,
320
+ end: node.endIndex,
321
+ });
322
+ }
323
+ function handleMethod(file, node, className, functions) {
324
+ const name = childByType(node, "name")?.text ?? null;
325
+ if (!name)
326
+ return;
327
+ const params = childByType(node, "formal_parameters");
328
+ const body = childByType(node, "compound_statement");
329
+ const isCtor = name === "__construct";
330
+ const key = isCtor ? `${className}.__construct` : `${className}.${name}`;
331
+ const label = isCtor ? `${className}` : key;
332
+ const info = {
333
+ key,
334
+ label: `${label}${getParamsLabel(params)}`,
335
+ params: declaredParamsOf(node),
336
+ file,
337
+ steps: body ? collectStatements(file, namedChildren(body), className) : [],
338
+ exported: !isPrivate(node),
339
+ start: node.startIndex,
340
+ end: node.endIndex,
341
+ };
342
+ functions.push(info);
343
+ if (isCtor) {
344
+ functions.push({
345
+ ...info,
346
+ key: `new ${className}`,
347
+ label: `${className}${getParamsLabel(params)}`,
348
+ params: declaredParamsOf(node),
349
+ });
350
+ }
351
+ }
352
+ function handleClass(file, node, functions) {
353
+ const className = childByType(node, "name")?.text ?? null;
354
+ if (!className)
355
+ return;
356
+ const body = childByType(node, "declaration_list");
357
+ if (!body)
358
+ return;
359
+ for (const member of namedChildren(body)) {
360
+ if (member.type === "method_declaration") {
361
+ handleMethod(file, member, className, functions);
362
+ }
363
+ }
364
+ }
365
+ function extractFromTree(file, _source, tree) {
366
+ const functions = [];
367
+ for (const stmt of namedChildren(tree.rootNode)) {
368
+ if (stmt.type === "function_definition") {
369
+ handleFunction(file, stmt, functions);
370
+ }
371
+ else if (stmt.type === "class_declaration") {
372
+ handleClass(file, stmt, functions);
373
+ }
374
+ else if (stmt.type === "namespace_definition") {
375
+ const body = childByType(stmt, "declaration_list") ??
376
+ childByType(stmt, "compound_statement");
377
+ if (body) {
378
+ for (const inner of namedChildren(body)) {
379
+ if (inner.type === "function_definition") {
380
+ handleFunction(file, inner, functions);
381
+ }
382
+ else if (inner.type === "class_declaration") {
383
+ handleClass(file, inner, functions);
384
+ }
385
+ }
386
+ }
387
+ }
388
+ }
389
+ return functions;
390
+ }
391
+ export const phpExtractor = {
392
+ id: "php",
393
+ extensions: [".php"],
394
+ grammarPackage: "tree-sitter-php",
395
+ grammarExport: "php",
396
+ extract: extractFromTree,
397
+ };
@@ -0,0 +1,2 @@
1
+ import { type LanguageExtractor } from "./types.js";
2
+ export declare const pythonExtractor: LanguageExtractor;