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,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialization of engine diff trees into the report's bounded per-file call
|
|
3
|
+
* flows. Everything here is a pure function of engine `DiffNode` results: the
|
|
4
|
+
* ASCII renderings stay untouched for the judgment context, and the structured
|
|
5
|
+
* trees are never parsed back out of that text.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Bounds per changed file. They exist so one huge file cannot push an unbounded
|
|
9
|
+
* report into the HTML, and every bound that drops content sets
|
|
10
|
+
* `CallFlowFile.truncated`.
|
|
11
|
+
*/
|
|
12
|
+
export const CALL_FLOW_MAX_ROOTS = 8;
|
|
13
|
+
/** Edges below a root. The engine already stops expanding at the same depth. */
|
|
14
|
+
export const CALL_FLOW_MAX_DEPTH = 4;
|
|
15
|
+
export const CALL_FLOW_MAX_CHILDREN = 8;
|
|
16
|
+
/**
|
|
17
|
+
* Extra children allowed per node beyond {@link CALL_FLOW_MAX_CHILDREN} when the
|
|
18
|
+
* callee is defined in another file. Without it a wide call graph drops exactly
|
|
19
|
+
* the calls a reader cannot see in the file under review.
|
|
20
|
+
*/
|
|
21
|
+
export const CALL_FLOW_MAX_CROSS_FILE_CHILDREN = 8;
|
|
22
|
+
export const CALL_FLOW_MAX_NODES = 160;
|
|
23
|
+
/**
|
|
24
|
+
* Files with actual text hunks. Units parsed from `diff --git` metadata (mode,
|
|
25
|
+
* rename, binary) carry a `File metadata` header and no hunk, so they never get
|
|
26
|
+
* a call-flow entry.
|
|
27
|
+
*/
|
|
28
|
+
function textHunkFiles(units) {
|
|
29
|
+
const files = new Set();
|
|
30
|
+
for (const unit of units) {
|
|
31
|
+
if (unit.header.startsWith("@@"))
|
|
32
|
+
files.add(unit.file);
|
|
33
|
+
}
|
|
34
|
+
return files;
|
|
35
|
+
}
|
|
36
|
+
/** Distinct changed-hunk files in report rank order; metadata-only files are excluded. */
|
|
37
|
+
export function reportOrderedTextHunkFiles(items, units) {
|
|
38
|
+
const withHunks = textHunkFiles(units);
|
|
39
|
+
const ordered = [];
|
|
40
|
+
const seen = new Set();
|
|
41
|
+
for (const item of items) {
|
|
42
|
+
if (!withHunks.has(item.file) || seen.has(item.file))
|
|
43
|
+
continue;
|
|
44
|
+
seen.add(item.file);
|
|
45
|
+
ordered.push(item.file);
|
|
46
|
+
}
|
|
47
|
+
return ordered;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Whether tree `node` is defined in `file`, calls into it anywhere below, or is
|
|
51
|
+
* a call the engine resolved to a definition in it. A caller several frames up
|
|
52
|
+
* is exactly the reach the report has to make visible, and a callee defined in
|
|
53
|
+
* `file` is a call this file's reader cannot see at all.
|
|
54
|
+
*/
|
|
55
|
+
export function treeTouchesFile(node, file) {
|
|
56
|
+
if (node.file === file || node.definition?.file === file)
|
|
57
|
+
return true;
|
|
58
|
+
return node.children.some(child => treeTouchesFile(child, file));
|
|
59
|
+
}
|
|
60
|
+
/** Bottom-up file relevance, used to prioritize branches within pruning bounds. */
|
|
61
|
+
function relevantNodes(root, file) {
|
|
62
|
+
const relevant = new Map();
|
|
63
|
+
const visit = (node) => {
|
|
64
|
+
let childHit = false;
|
|
65
|
+
for (const child of node.children) {
|
|
66
|
+
if (visit(child))
|
|
67
|
+
childHit = true;
|
|
68
|
+
}
|
|
69
|
+
const hit = node.file === file || node.definition?.file === file || childHit;
|
|
70
|
+
relevant.set(node, hit);
|
|
71
|
+
return hit;
|
|
72
|
+
};
|
|
73
|
+
visit(root);
|
|
74
|
+
return relevant;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Derive report statuses bottom-up. The engine's `same`/`added`/`removed` says
|
|
78
|
+
* nothing about a caller whose own definition is unchanged but whose callee
|
|
79
|
+
* changed, so a `same` node with any changed descendant becomes `changed`.
|
|
80
|
+
* Children are visited before the parent, and this runs on the whole engine
|
|
81
|
+
* tree, so a branch a later bound drops still leaves its ancestors marked.
|
|
82
|
+
*/
|
|
83
|
+
function deriveStatuses(node, derived) {
|
|
84
|
+
let changedChild = false;
|
|
85
|
+
for (const child of node.children) {
|
|
86
|
+
if (deriveStatuses(child, derived) !== "same")
|
|
87
|
+
changedChild = true;
|
|
88
|
+
}
|
|
89
|
+
const status = node.status !== "same" ? node.status : changedChild ? "changed" : "same";
|
|
90
|
+
derived.set(node, status);
|
|
91
|
+
return status;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Priority for one child within its file's view, lowest first. Branches that
|
|
95
|
+
* reach the file outrank branches that do not, and a changed branch outranks an
|
|
96
|
+
* unchanged one, so a bounded file keeps what the diff actually moved.
|
|
97
|
+
*/
|
|
98
|
+
function childPriority(child, view, derived) {
|
|
99
|
+
const changed = derived.get(child) !== "same";
|
|
100
|
+
const relevant = view.relevant.get(child) === true;
|
|
101
|
+
if (relevant)
|
|
102
|
+
return changed ? 0 : 1;
|
|
103
|
+
return changed ? 2 : 3;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Children to serialize under `node`, in source order.
|
|
107
|
+
*
|
|
108
|
+
* Retain caller and callee context across files. When the breadth bound cuts
|
|
109
|
+
* children, paths reaching this file and changed branches win the budget, and a
|
|
110
|
+
* callee defined in another file gets a second allowance on top of the regular
|
|
111
|
+
* one: that call is the reach the reader cannot see in this file at all.
|
|
112
|
+
* Survivors keep source order; scoping must not silently hide downstream calls.
|
|
113
|
+
*/
|
|
114
|
+
function visibleChildren(node, view, derived, budget) {
|
|
115
|
+
const candidates = node.children;
|
|
116
|
+
if (candidates.length <= CALL_FLOW_MAX_CHILDREN)
|
|
117
|
+
return candidates;
|
|
118
|
+
const ranked = [...candidates].sort((left, right) => childPriority(left, view, derived) - childPriority(right, view, derived));
|
|
119
|
+
const kept = new Set(ranked.slice(0, CALL_FLOW_MAX_CHILDREN));
|
|
120
|
+
const callerFile = node.definition?.file ?? node.file;
|
|
121
|
+
let extra = 0;
|
|
122
|
+
for (const child of ranked.slice(CALL_FLOW_MAX_CHILDREN)) {
|
|
123
|
+
if (extra >= CALL_FLOW_MAX_CROSS_FILE_CHILDREN)
|
|
124
|
+
break;
|
|
125
|
+
const calleeFile = child.definition?.file;
|
|
126
|
+
if (calleeFile === undefined || calleeFile === callerFile)
|
|
127
|
+
continue;
|
|
128
|
+
kept.add(child);
|
|
129
|
+
extra += 1;
|
|
130
|
+
}
|
|
131
|
+
// Only a call that actually left the report is a truncation: the extra
|
|
132
|
+
// allowance can cover a wide node completely, and claiming a cut that never
|
|
133
|
+
// happened would make the flag mean nothing.
|
|
134
|
+
if (kept.size < candidates.length)
|
|
135
|
+
budget.truncated = true;
|
|
136
|
+
return candidates.filter(child => kept.has(child));
|
|
137
|
+
}
|
|
138
|
+
function serializeNode(node, depth, view, derived, budget, detail) {
|
|
139
|
+
if (budget.remaining <= 0) {
|
|
140
|
+
budget.truncated = true;
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
budget.remaining -= 1;
|
|
144
|
+
const children = [];
|
|
145
|
+
if (depth >= CALL_FLOW_MAX_DEPTH) {
|
|
146
|
+
if (node.children.length > 0)
|
|
147
|
+
budget.truncated = true;
|
|
148
|
+
}
|
|
149
|
+
else if (node.children.length > 0) {
|
|
150
|
+
const visible = visibleChildren(node, view, derived, budget);
|
|
151
|
+
// Spend the shared budget on relevant changes first, then restore source
|
|
152
|
+
// order. Otherwise a wide early sibling can hide a late changed call.
|
|
153
|
+
const ranked = [...visible].sort((left, right) => childPriority(left, view, derived) - childPriority(right, view, derived));
|
|
154
|
+
const serializedChildren = new Map();
|
|
155
|
+
for (const child of ranked) {
|
|
156
|
+
const childNode = serializeNode(child, depth + 1, view, derived, budget, detail);
|
|
157
|
+
if (childNode === null)
|
|
158
|
+
break;
|
|
159
|
+
serializedChildren.set(child, childNode);
|
|
160
|
+
}
|
|
161
|
+
for (const child of visible) {
|
|
162
|
+
const childNode = serializedChildren.get(child);
|
|
163
|
+
if (childNode)
|
|
164
|
+
children.push(childNode);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// SAFETY: deriveStatuses walked this tree before serialization, so every
|
|
168
|
+
// visited node has an entry; the fallback only satisfies the Map's type.
|
|
169
|
+
const serialized = {
|
|
170
|
+
key: node.key,
|
|
171
|
+
label: node.label,
|
|
172
|
+
status: derived.get(node) ?? "same",
|
|
173
|
+
children,
|
|
174
|
+
};
|
|
175
|
+
if (node.file !== undefined)
|
|
176
|
+
serialized.file = node.file;
|
|
177
|
+
if (node.line !== undefined)
|
|
178
|
+
serialized.line = node.line;
|
|
179
|
+
if (node.endLine !== undefined)
|
|
180
|
+
serialized.endLine = node.endLine;
|
|
181
|
+
const resolved = detail?.(node);
|
|
182
|
+
if (resolved?.description !== undefined)
|
|
183
|
+
serialized.description = resolved.description;
|
|
184
|
+
if (resolved?.source !== undefined)
|
|
185
|
+
serialized.source = resolved.source;
|
|
186
|
+
return serialized;
|
|
187
|
+
}
|
|
188
|
+
function buildCallFlowFile(file, trees, detail) {
|
|
189
|
+
const budget = { remaining: CALL_FLOW_MAX_NODES, truncated: false };
|
|
190
|
+
const roots = [];
|
|
191
|
+
const seen = new Set();
|
|
192
|
+
for (const tree of trees) {
|
|
193
|
+
if (!treeTouchesFile(tree.tree, file))
|
|
194
|
+
continue;
|
|
195
|
+
// A definition has one diff in a snapshot pair. Deduplicate roots without
|
|
196
|
+
// serializing their potentially large subtrees just to compare identity.
|
|
197
|
+
const signature = JSON.stringify([tree.tree.key, tree.tree.file, tree.tree.line, tree.tree.status]);
|
|
198
|
+
if (seen.has(signature))
|
|
199
|
+
continue;
|
|
200
|
+
seen.add(signature);
|
|
201
|
+
if (roots.length >= CALL_FLOW_MAX_ROOTS) {
|
|
202
|
+
budget.truncated = true;
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
const derived = new Map();
|
|
206
|
+
deriveStatuses(tree.tree, derived);
|
|
207
|
+
const view = { relevant: relevantNodes(tree.tree, file) };
|
|
208
|
+
const root = serializeNode(tree.tree, 0, view, derived, budget, detail);
|
|
209
|
+
if (root === null)
|
|
210
|
+
break;
|
|
211
|
+
roots.push(root);
|
|
212
|
+
}
|
|
213
|
+
return { file, trees: roots, truncated: budget.truncated };
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* One bounded entry per file with actual text hunks that at least one tree
|
|
217
|
+
* reaches, in the order given. Files no tree reaches are omitted rather than
|
|
218
|
+
* reported as an empty tree. `detail` adds definition source and prose; without
|
|
219
|
+
* it the trees carry structure only.
|
|
220
|
+
*/
|
|
221
|
+
export function buildCallFlows(files, trees, detail) {
|
|
222
|
+
const entries = [];
|
|
223
|
+
for (const file of files) {
|
|
224
|
+
const entry = buildCallFlowFile(file, trees, detail);
|
|
225
|
+
if (entry.trees.length > 0)
|
|
226
|
+
entries.push(entry);
|
|
227
|
+
}
|
|
228
|
+
return entries;
|
|
229
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local, deterministic facts about the added and removed lines of one hunk.
|
|
3
|
+
*
|
|
4
|
+
* Without any model and without the text leaving the machine, it answers
|
|
5
|
+
* existence questions that depend on what the file is. Code: did a condition or
|
|
6
|
+
* comparison change, a limit, an input check, and did the lines hand an error to
|
|
7
|
+
* the caller, defer it, or discard it. Documentation: did an instruction to
|
|
8
|
+
* readers, a link target, or a numeric limit change. Configuration: was a CI gate
|
|
9
|
+
* weakened, did permissions or secret access change, a version pin, a limit. Each
|
|
10
|
+
* `yes` carries the line that produced it, so a reviewer sees what it is about.
|
|
11
|
+
*
|
|
12
|
+
* The analysis is lexical, not a parse: in code, strings become a placeholder and
|
|
13
|
+
* comments are removed; in configuration only comments are; and patterns are
|
|
14
|
+
* matched on what remains, on the changed lines of
|
|
15
|
+
* each side and on the lines around them that the hunk shows. That keeps it usable
|
|
16
|
+
* on a patch with no repository, and it keeps its limits plain:
|
|
17
|
+
*
|
|
18
|
+
* - only file types listed here are read; any other file answers no question
|
|
19
|
+
* at all, never `no`;
|
|
20
|
+
* - `no` means the changed lines the hunk shows contain no such pattern, never
|
|
21
|
+
* that the property is absent from the file or the program;
|
|
22
|
+
* - a line moved without change cancels out, because every question compares
|
|
23
|
+
* what the removed lines had with what the added lines have.
|
|
24
|
+
*/
|
|
25
|
+
import type { ReviewUnit } from "./types.js";
|
|
26
|
+
/** Questions asked of source code, in the order the report shows them. */
|
|
27
|
+
export declare const CODE_FACT_QUESTIONS: readonly ["comparisonChanged", "limitChanged", "validationChanged", "failurePropagated", "failureDeferred", "failureDiscarded", "contractChanged", "dataChanged", "queryChanged"];
|
|
28
|
+
/** Questions asked of SQL files: schema and data changes. */
|
|
29
|
+
export declare const SQL_FACT_QUESTIONS: readonly ["dataChanged"];
|
|
30
|
+
/** Questions asked of prose (documentation): what a reader is told to do or rely on. */
|
|
31
|
+
export declare const PROSE_FACT_QUESTIONS: readonly ["instructionChanged", "referenceChanged", "limitChanged"];
|
|
32
|
+
/** Questions asked of configuration: CI gates, permissions, pins, and bounds. */
|
|
33
|
+
export declare const CONFIG_FACT_QUESTIONS: readonly ["gateWeakened", "permissionChanged", "pinChanged", "limitChanged"];
|
|
34
|
+
/** Every question, once, in report order. */
|
|
35
|
+
export declare const CHANGE_FACT_QUESTIONS: readonly ["comparisonChanged", "limitChanged", "validationChanged", "failurePropagated", "failureDeferred", "failureDiscarded", "contractChanged", "dataChanged", "queryChanged", "instructionChanged", "referenceChanged", "gateWeakened", "permissionChanged", "pinChanged"];
|
|
36
|
+
export type ChangeFactQuestion = (typeof CHANGE_FACT_QUESTIONS)[number];
|
|
37
|
+
export type ChangeFactAnswer = "yes" | "no";
|
|
38
|
+
/** Source families: how comments and strings are written, and whether indentation is syntax. */
|
|
39
|
+
export type CodeLanguage = "c-like" | "python" | "ruby";
|
|
40
|
+
/** What kind of text a file is, and so which questions apply to it. */
|
|
41
|
+
export type ChangeFactLanguage = CodeLanguage | "sql" | "prose" | "config";
|
|
42
|
+
/** The changed line a `yes` rests on, exactly as the diff shows it. */
|
|
43
|
+
export interface ChangeFactEvidence {
|
|
44
|
+
readonly side: "added" | "removed";
|
|
45
|
+
readonly text: string;
|
|
46
|
+
}
|
|
47
|
+
export interface ChangeFacts {
|
|
48
|
+
/** Null when this analysis cannot read the file type; then no question is answered. */
|
|
49
|
+
readonly language: ChangeFactLanguage | null;
|
|
50
|
+
/**
|
|
51
|
+
* True when the removed and added text are the same once comments and layout
|
|
52
|
+
* (for prose, line breaks and spacing) are ignored. Null for an unread type.
|
|
53
|
+
*/
|
|
54
|
+
readonly inert: boolean | null;
|
|
55
|
+
/**
|
|
56
|
+
* True when every changed code line is an import (a module import, `require`,
|
|
57
|
+
* `using`, or a name inside a multi-line import list): wiring that other hunks
|
|
58
|
+
* put to use. False for other kinds of text, and null for an unread type.
|
|
59
|
+
*/
|
|
60
|
+
readonly importsOnly?: boolean;
|
|
61
|
+
/** Exactly the questions {@link factQuestionsFor} lists for the language. */
|
|
62
|
+
readonly answers: Readonly<Partial<Record<ChangeFactQuestion, ChangeFactAnswer>>>;
|
|
63
|
+
readonly evidence: Readonly<Partial<Record<ChangeFactQuestion, ChangeFactEvidence>>>;
|
|
64
|
+
}
|
|
65
|
+
export declare function changeFactLanguageOf(file: string): ChangeFactLanguage | null;
|
|
66
|
+
/** The questions a file of this kind is asked; none for an unread type. */
|
|
67
|
+
export declare function factQuestionsFor(language: ChangeFactLanguage | null): readonly ChangeFactQuestion[];
|
|
68
|
+
/** The facts for one hunk, each `yes` with the changed line it rests on. */
|
|
69
|
+
export declare function changeFactsOf(unit: Pick<ReviewUnit, "file" | "diff">): ChangeFacts;
|