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,268 @@
1
+ import { heuristicCallSyntax } from "./call-syntax.js";
2
+ import { childByType, collapseWs, locFromNode, namedChildren, } from "./types.js";
3
+ function isPrivate(node) {
4
+ const mods = childByType(node, "modifiers");
5
+ if (!mods)
6
+ return false;
7
+ return /\bprivate\b|\bfileprivate\b/.test(mods.text);
8
+ }
9
+ function isLikelyTypeName(name) {
10
+ const c = name[0];
11
+ return c !== undefined && c === c.toUpperCase() && c !== c.toLowerCase();
12
+ }
13
+ function getParamsLabel(node) {
14
+ const params = namedChildren(node).filter((c) => c.type === "parameter");
15
+ if (params.length === 0)
16
+ return "()";
17
+ const names = [];
18
+ for (const p of params) {
19
+ // Prefer external/local simple_identifier; last id is usually the local name
20
+ const ids = namedChildren(p).filter((c) => c.type === "simple_identifier");
21
+ names.push(ids.at(-1)?.text ?? "_");
22
+ }
23
+ return `(${names.join(", ")})`;
24
+ }
25
+ function navigationProp(nav) {
26
+ const suffix = childByType(nav, "navigation_suffix");
27
+ const id = suffix ? childByType(suffix, "simple_identifier") : null;
28
+ return id?.text ?? null;
29
+ }
30
+ function calleeKey(node, className) {
31
+ if (node.type === "simple_identifier") {
32
+ if (isLikelyTypeName(node.text))
33
+ return `new ${node.text}`;
34
+ return node.text;
35
+ }
36
+ if (node.type === "navigation_expression") {
37
+ const object = node.namedChild(0);
38
+ const prop = navigationProp(node);
39
+ if (!object || !prop)
40
+ return null;
41
+ if (object.type === "self_expression" && className) {
42
+ return `${className}.${prop}`;
43
+ }
44
+ if (object.type === "simple_identifier") {
45
+ return `${object.text}.${prop}`;
46
+ }
47
+ if (className)
48
+ return `${className}.${prop}`;
49
+ return prop;
50
+ }
51
+ return null;
52
+ }
53
+ function statementsOf(body) {
54
+ if (!body)
55
+ return [];
56
+ if (body.type === "function_body") {
57
+ const stmts = childByType(body, "statements");
58
+ return stmts ? namedChildren(stmts) : [];
59
+ }
60
+ if (body.type === "statements")
61
+ return namedChildren(body);
62
+ return [body];
63
+ }
64
+ function collectStatements(file, statements, className) {
65
+ const steps = [];
66
+ const seen = new Set();
67
+ const addCall = (key, node) => {
68
+ const mark = `${key}:${node.startIndex}`;
69
+ if (seen.has(mark))
70
+ return;
71
+ seen.add(mark);
72
+ const step = { type: "call", key, ...locFromNode(file, node) };
73
+ step.syntax = heuristicCallSyntax(node, key);
74
+ steps.push(step);
75
+ };
76
+ const pushIfChain = (node, asElseIf) => {
77
+ const kids = namedChildren(node);
78
+ const stmtBlocks = kids.filter((c) => c.type === "statements");
79
+ const nestedIf = kids.find((c) => c.type === "if_statement") ?? null;
80
+ const cond = kids.find((c) => c.type !== "statements" &&
81
+ c.type !== "else" &&
82
+ c.type !== "if_statement") ?? null;
83
+ const condText = cond ? collapseWs(cond.text) : "";
84
+ const kind = asElseIf ? "else-if" : "if";
85
+ const labelKind = asElseIf ? "else if" : "if";
86
+ steps.push({
87
+ type: "branch",
88
+ key: condText ? `${kind}:${condText}` : kind,
89
+ label: condText ? `${labelKind} ${condText}` : labelKind,
90
+ ...locFromNode(file, cond ?? node),
91
+ children: collectStatements(file, statementsOf(stmtBlocks[0] ?? null), className),
92
+ });
93
+ if (nestedIf) {
94
+ pushIfChain(nestedIf, true);
95
+ return;
96
+ }
97
+ if (stmtBlocks[1]) {
98
+ steps.push({
99
+ type: "branch",
100
+ key: "else",
101
+ label: "else",
102
+ ...locFromNode(file, stmtBlocks[1]),
103
+ children: collectStatements(file, statementsOf(stmtBlocks[1]), className),
104
+ });
105
+ }
106
+ };
107
+ const walk = (node) => {
108
+ if (node.type === "function_declaration" ||
109
+ node.type === "init_declaration" ||
110
+ node.type === "class_declaration" ||
111
+ node.type === "lambda_literal") {
112
+ return;
113
+ }
114
+ if (node.type === "if_statement") {
115
+ pushIfChain(node, false);
116
+ return;
117
+ }
118
+ if (node.type === "do_statement") {
119
+ const doBody = childByType(node, "statements");
120
+ steps.push({
121
+ type: "branch",
122
+ key: "do",
123
+ label: "do",
124
+ ...locFromNode(file, node),
125
+ children: doBody
126
+ ? collectStatements(file, namedChildren(doBody), className)
127
+ : [],
128
+ });
129
+ for (const clause of namedChildren(node)) {
130
+ if (clause.type === "catch_block") {
131
+ const body = childByType(clause, "statements");
132
+ steps.push({
133
+ type: "branch",
134
+ key: "catch",
135
+ label: "catch",
136
+ ...locFromNode(file, clause),
137
+ children: body
138
+ ? collectStatements(file, namedChildren(body), className)
139
+ : [],
140
+ });
141
+ }
142
+ }
143
+ return;
144
+ }
145
+ if (node.type === "switch_statement") {
146
+ for (const entry of namedChildren(node)) {
147
+ if (entry.type !== "switch_entry")
148
+ continue;
149
+ const pattern = childByType(entry, "switch_pattern");
150
+ const isDefault = namedChildren(entry).some((c) => c.type === "default_keyword");
151
+ const body = childByType(entry, "statements");
152
+ if (isDefault || !pattern) {
153
+ steps.push({
154
+ type: "branch",
155
+ key: "default",
156
+ label: "default",
157
+ ...locFromNode(file, entry),
158
+ children: body
159
+ ? collectStatements(file, namedChildren(body), className)
160
+ : [],
161
+ });
162
+ }
163
+ else {
164
+ const text = collapseWs(pattern.text);
165
+ steps.push({
166
+ type: "branch",
167
+ key: text ? `case:${text}` : "case",
168
+ label: text ? `case ${text}` : "case",
169
+ ...locFromNode(file, pattern),
170
+ children: body
171
+ ? collectStatements(file, namedChildren(body), className)
172
+ : [],
173
+ });
174
+ }
175
+ }
176
+ return;
177
+ }
178
+ if (node.type === "call_expression") {
179
+ const callee = node.namedChild(0);
180
+ if (callee) {
181
+ const key = calleeKey(callee, className);
182
+ if (key)
183
+ addCall(key, node);
184
+ }
185
+ for (const child of namedChildren(node).slice(1))
186
+ walk(child);
187
+ return;
188
+ }
189
+ // Unwrap try openIt() → still see the call
190
+ if (node.type === "try_expression") {
191
+ for (const child of namedChildren(node))
192
+ walk(child);
193
+ return;
194
+ }
195
+ for (const child of namedChildren(node))
196
+ walk(child);
197
+ };
198
+ for (const stmt of statements)
199
+ walk(stmt);
200
+ return steps;
201
+ }
202
+ function handleFunction(file, node, className, functions) {
203
+ const name = childByType(node, "simple_identifier")?.text ?? null;
204
+ if (!name)
205
+ return;
206
+ const body = childByType(node, "function_body");
207
+ const key = className ? `${className}.${name}` : name;
208
+ functions.push({
209
+ key,
210
+ label: `${key}${getParamsLabel(node)}`,
211
+ file,
212
+ steps: collectStatements(file, statementsOf(body), className),
213
+ exported: !isPrivate(node),
214
+ start: node.startIndex,
215
+ end: node.endIndex,
216
+ });
217
+ }
218
+ function handleInit(file, node, className, functions) {
219
+ const body = childByType(node, "function_body");
220
+ const info = {
221
+ key: `${className}.init`,
222
+ label: `${className}${getParamsLabel(node)}`,
223
+ file,
224
+ steps: collectStatements(file, statementsOf(body), className),
225
+ exported: !isPrivate(node),
226
+ start: node.startIndex,
227
+ end: node.endIndex,
228
+ };
229
+ functions.push(info);
230
+ functions.push({ ...info, key: `new ${className}` });
231
+ }
232
+ function handleClass(file, node, functions) {
233
+ const className = childByType(node, "type_identifier")?.text ?? null;
234
+ if (!className)
235
+ return;
236
+ const body = childByType(node, "class_body");
237
+ if (!body)
238
+ return;
239
+ for (const element of namedChildren(body)) {
240
+ if (element.type === "function_declaration") {
241
+ handleFunction(file, element, className, functions);
242
+ }
243
+ else if (element.type === "init_declaration") {
244
+ handleInit(file, element, className, functions);
245
+ }
246
+ else if (element.type === "class_declaration") {
247
+ handleClass(file, element, functions);
248
+ }
249
+ }
250
+ }
251
+ function extractFromTree(file, _source, tree) {
252
+ const functions = [];
253
+ for (const stmt of namedChildren(tree.rootNode)) {
254
+ if (stmt.type === "function_declaration") {
255
+ handleFunction(file, stmt, null, functions);
256
+ }
257
+ else if (stmt.type === "class_declaration") {
258
+ handleClass(file, stmt, functions);
259
+ }
260
+ }
261
+ return functions;
262
+ }
263
+ export const swiftExtractor = {
264
+ id: "swift",
265
+ extensions: [".swift"],
266
+ grammarPackage: "tree-sitter-swift",
267
+ extract: extractFromTree,
268
+ };
@@ -0,0 +1,36 @@
1
+ import type Parser from "tree-sitter";
2
+ import type { DeclaredParams, FunctionInfo, SourceLoc } from "../types.js";
3
+ export type SyntaxNode = Parser.SyntaxNode;
4
+ export type Tree = Parser.Tree;
5
+ export interface LanguageExtractor {
6
+ /** Stable id, e.g. "typescript" | "python" | "go" */
7
+ id: string;
8
+ /** File extensions including dot, lowercase */
9
+ extensions: string[];
10
+ /** npm package providing the tree-sitter grammar */
11
+ grammarPackage: string;
12
+ /** Named export on the grammar package, if any (e.g. "typescript", "tsx") */
13
+ grammarExport?: string;
14
+ extract(file: string, source: string, tree: Tree): FunctionInfo[];
15
+ }
16
+ export declare function namedChildren(node: SyntaxNode): SyntaxNode[];
17
+ /**
18
+ * Whether two handles name the same syntax node. The native binding may return
19
+ * a fresh JS object for a node on each access, and whether it does depends on
20
+ * garbage collection, so `===` on nodes gives different answers from run to run.
21
+ * A node's id is stable within its tree.
22
+ */
23
+ export declare function sameNode(a: SyntaxNode | null | undefined, b: SyntaxNode | null | undefined): boolean;
24
+ export declare function childByType(node: SyntaxNode, type: string): SyntaxNode | null;
25
+ export declare function collapseWs(text: string): string;
26
+ /**
27
+ * Call-site / branch span for a syntax node.
28
+ * Uses tree-sitter 0-based rows → 1-based display lines.
29
+ */
30
+ export declare function locFromNode(file: string, node: SyntaxNode): SourceLoc;
31
+ /**
32
+ * Declared parameter list of a definition, read from the AST: the verbatim
33
+ * list text, with no slots. Text alone keeps argument binding `unknown`, which
34
+ * is what the extractors that do not build lexical scopes can honestly claim.
35
+ */
36
+ export declare function declaredParamsOf(node: SyntaxNode): DeclaredParams | undefined;
@@ -0,0 +1,74 @@
1
+ import { parameterText, textOnlyParams } from "./call-syntax.js";
2
+ export function namedChildren(node) {
3
+ const out = [];
4
+ for (let i = 0; i < node.namedChildCount; i++) {
5
+ const child = node.namedChild(i);
6
+ if (child)
7
+ out.push(child);
8
+ }
9
+ return out;
10
+ }
11
+ /**
12
+ * Whether two handles name the same syntax node. The native binding may return
13
+ * a fresh JS object for a node on each access, and whether it does depends on
14
+ * garbage collection, so `===` on nodes gives different answers from run to run.
15
+ * A node's id is stable within its tree.
16
+ */
17
+ export function sameNode(a, b) {
18
+ return a !== null && a !== undefined && b !== null && b !== undefined && a.id === b.id;
19
+ }
20
+ export function childByType(node, type) {
21
+ return namedChildren(node).find((c) => c.type === type) ?? null;
22
+ }
23
+ export function collapseWs(text) {
24
+ return text.replace(/\s+/g, " ").trim();
25
+ }
26
+ /**
27
+ * Call-site / branch span for a syntax node.
28
+ * Uses tree-sitter 0-based rows → 1-based display lines.
29
+ */
30
+ export function locFromNode(file, node) {
31
+ const line = node.startPosition.row + 1;
32
+ const endLine = node.endPosition.row + 1;
33
+ return endLine > line ? { file, line, endLine } : { file, line };
34
+ }
35
+ /**
36
+ * Parameter-list containers the grammars declare. A list is a direct child of
37
+ * the definition node, or of its declarator (`int callee(int param);`).
38
+ */
39
+ const PARAMETER_CONTAINERS = {
40
+ formal_parameters: true,
41
+ parameters: true,
42
+ parameter_list: true,
43
+ method_parameters: true,
44
+ function_value_parameters: true,
45
+ lambda_parameters: true,
46
+ parameter_clause: true,
47
+ };
48
+ /** Nodes that hold a parameter list one level below the definition. */
49
+ const PARAMETER_DECLARATORS = {
50
+ function_declarator: true,
51
+ declarator: true,
52
+ method_declarator: true,
53
+ call_signature: true,
54
+ function_declarator_body: true,
55
+ };
56
+ function namedChildrenTyped(node, types) {
57
+ return namedChildren(node).filter((child) => types[child.type] === true);
58
+ }
59
+ /**
60
+ * Declared parameter list of a definition, read from the AST: the verbatim
61
+ * list text, with no slots. Text alone keeps argument binding `unknown`, which
62
+ * is what the extractors that do not build lexical scopes can honestly claim.
63
+ */
64
+ export function declaredParamsOf(node) {
65
+ const direct = namedChildrenTyped(node, PARAMETER_CONTAINERS)[0];
66
+ if (direct)
67
+ return textOnlyParams(parameterText(direct));
68
+ for (const declarator of namedChildrenTyped(node, PARAMETER_DECLARATORS)) {
69
+ const nested = namedChildrenTyped(declarator, PARAMETER_CONTAINERS)[0];
70
+ if (nested)
71
+ return textOnlyParams(parameterText(nested));
72
+ }
73
+ return undefined;
74
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * TypeScript / TSX type contracts for review context.
3
+ *
4
+ * An interface, type alias, or enum is syntactic evidence about a shape, not a
5
+ * callable: the entries this helper adds carry `review.kind`, no steps, and the
6
+ * whole declaration span, and the extractor keeps them out of the callable
7
+ * index. What they *do* carry is `review.references`: the type names written in
8
+ * a definition's signature, body, or declaration — `Promise<Foo>`,
9
+ * `x as Bar`, `interface A extends B`, `foo<Baz>()`, `import("m").Q` — each
10
+ * with the module specifier and original name it was written through.
11
+ *
12
+ * {@link resolveTypeContracts} turns those references into snapshot-local
13
+ * edges. Relative imports bind to snapshot paths; a bare or aliased module
14
+ * path binds only when one snapshot file's path suffix matches it. Unresolved
15
+ * imports stay unresolved, even when another file has a unique same-named
16
+ * declaration. Unimported names prefer the same file, then a unique snapshot
17
+ * candidate. These are syntactic candidates, not TypeScript symbol resolution.
18
+ *
19
+ * Every step is derived from the source and the snapshot declarations, so the
20
+ * same input always yields the same edges.
21
+ *
22
+ * Deliberate limits: only module-level declarations are extracted; references
23
+ * in module-level value code, class field annotations, and heritage clauses
24
+ * belong to no definition and are dropped; re-export/barrel hops are not
25
+ * followed; a default import is matched by its local binding name; a
26
+ * declaration that names itself is not an edge. External types absent from
27
+ * the snapshot remain unresolved.
28
+ */
29
+ import type Parser from "tree-sitter";
30
+ import type { FunctionInfo } from "../types.js";
31
+ type Tree = Parser.Tree;
32
+ /**
33
+ * Record the type contracts of one file: append a non-callable definition per
34
+ * interface / type alias / enum, then attach each written reference to the
35
+ * innermost definition (callable or contract) whose span contains it. A
36
+ * reference in module-level code that belongs to no definition is left out
37
+ * rather than credited to a sibling.
38
+ */
39
+ export declare function extractTypeContracts(file: string, tree: Tree, functions: FunctionInfo[]): void;
40
+ /** One `owner -> target` type-contract relation for the context graph. */
41
+ export interface TypeContractEdge {
42
+ owner: FunctionInfo;
43
+ target: FunctionInfo;
44
+ evidence: string;
45
+ kind: "contract";
46
+ /** 1-based line of the written reference, not of either definition. */
47
+ line: number;
48
+ }
49
+ /**
50
+ * Resolve one reference against the snapshot. A relative specifier must name a
51
+ * snapshot file (exact binding); a bare or aliased specifier binds only when
52
+ * exactly one snapshot file's path ends with its tail; a name written without a
53
+ * module binds to the file's own declaration. Only a name no module explains
54
+ * may fall back to a globally unique declaration.
55
+ */
56
+ export declare function resolveTypeContracts(functions: readonly FunctionInfo[]): TypeContractEdge[];
57
+ export {};