@dev.fast/whiteboard 0.5.2-preview.20261104.147 → 0.5.2-preview.20261109.149
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/dist/{account-alias-DXpd0Px8.js → account-alias-Cs5YqXRj.js} +4 -4
- package/dist/agent-cli-DdUAmdca.js +2 -0
- package/dist/{agent-cli-COrZtFks.js → agent-cli-a5J-juuu.js} +8 -8
- package/dist/{agent-client-BFtYm3Ng.js → agent-client-CgnEo6lf.js} +3 -3
- package/dist/{authoring-tools-D1avYp8-.js → authoring-tools-BgZvnbjN.js} +3 -3
- package/dist/{background-server-HOJozY99.js → background-server-D8SaPvuC.js} +1 -1
- package/dist/{background-server-BiRSqjxG.js → background-server-DHEcsFwH.js} +4 -4
- package/dist/build-info.json +1 -1
- package/dist/{cli-CSlwGRvH.js → cli-Bq5zVqlc.js} +1 -1
- package/dist/{cli-runner-CuffXA0Q.js → cli-runner-hL2efcxb.js} +21 -21
- package/dist/cli.js +1 -1
- package/dist/{fuzzy-match-DEo941za.js → fuzzy-match-DNyQDN3P.js} +2 -2
- package/dist/{headless-host-BCkXVVpU.js → headless-host-CGyfb5mS.js} +1 -1
- package/dist/{headless-host-CIuJJjmM.js → headless-host-bb09yVkX.js} +17 -15
- package/dist/{import-CjcW7EIQ.js → import-_XAsWqen.js} +24 -139
- package/dist/{local-data-B5PBZ0Ge.js → local-data-ZQIkF5k1.js} +81 -70
- package/dist/{mcp-Ba3WvhUh.js → mcp-B-J8P5xm.js} +4 -4
- package/dist/{package-paths-Dk7MOXxN.js → package-paths-wobHueCx.js} +1 -1
- package/dist/profile-Bi2SbpSI.js +2 -0
- package/dist/{profile-CNMhLUhf.js → profile-D-SbO3p9.js} +2 -2
- package/dist/{remote-attach-DkZoYBHV.js → remote-attach-DyIESbbf.js} +4 -4
- package/dist/{remote-extensions-BvV29_gk.js → remote-extensions-BHHFPyYW.js} +1 -1
- package/dist/{remote-extensions-L95HNwIH.js → remote-extensions-gTMcRBg-.js} +2 -2
- package/dist/{remote-language-server-l4ConTfj.js → remote-language-server-Pp261dqJ.js} +4 -4
- package/dist/{remote-uninstall-BAQM7cU8.js → remote-uninstall-D_hSuBik.js} +5 -5
- package/dist/{request-origin-DZexKlc4.js → request-origin-ENYd0Ymr.js} +1 -1
- package/dist/{review-app-launcher-B5F10y_4.js → review-app-launcher-DR5vYGEl.js} +1 -1
- package/dist/{review-home-paths-BmZX2qiz.js → review-home-paths-B8909D07.js} +19 -19
- package/dist/{review-telemetry-kQ7esDRE.js → review-telemetry-CxNvwdDS.js} +4 -4
- package/dist/server/desktop-host.js +74 -16
- package/dist/{server-discovery-DYY_xeG9.js → server-discovery-Fme7f3fb.js} +2 -2
- package/dist/sharing/index.d.ts +21 -21
- package/dist/sharing/index.js +1 -1
- package/dist/{src-DirPN_Qh.js → src-BPrngiWX.js} +1769 -1
- package/dist/{stored-document-migration-vg0NAzXG.js → stored-document-migration-BQcUyXO8.js} +4 -73
- package/dist/{tool-failure-BLBwcl3H.js → tool-failure-Cgjidoud.js} +5 -5
- package/package.json +5 -6
- package/src/review-api/comparison-coverage.ts +6 -20
- package/src/review-api/http.ts +20 -16
- package/src/review-api/review-progress.ts +38 -123
- package/src/review-api/store.ts +4 -6
- package/src/server/review-gateway-pushes.ts +5 -1
- package/src/server/review-gateway.ts +15 -1
- package/src/software-map-diff-counts.ts +4 -2
- package/src/viewed-coverage.ts +9 -252
- package/dist/agent-cli-x6-Eh1S-.js +0 -2
- package/dist/profile-BstQkIY0.js +0 -2
- package/src/review-api/file-lenses.ts +0 -125
- package/src/unified-diff.ts +0 -71
- package/dist/{s3-CsG2EWED.js → s3-d8RGPKwt.js} +1 -1
package/src/viewed-coverage.ts
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
import { structuralChangeCounts } from "@dev.fast/review-protocol";
|
|
2
|
-
import {
|
|
3
|
-
type FileLineRange,
|
|
4
|
-
type LineInterval,
|
|
5
|
-
unionIntervals,
|
|
6
|
-
} from "@dev.fast/whiteboard-document";
|
|
7
1
|
import { z } from "zod";
|
|
8
2
|
|
|
9
|
-
export {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
export {
|
|
4
|
+
type CoverageFile,
|
|
5
|
+
type CoverageProgress,
|
|
6
|
+
coverageProgress,
|
|
7
|
+
coverageSources,
|
|
8
|
+
emptyCoverage,
|
|
9
|
+
mergeCoverageProgress,
|
|
10
|
+
scopedCoverage,
|
|
11
|
+
} from "@dev.fast/whiteboard-document";
|
|
15
12
|
|
|
16
13
|
export const coverageSchema = z.object({
|
|
17
14
|
base: z.array(
|
|
@@ -21,243 +18,3 @@ export const coverageSchema = z.object({
|
|
|
21
18
|
z.tuple([z.number().int().nonnegative(), z.number().int().nonnegative()]),
|
|
22
19
|
),
|
|
23
20
|
});
|
|
24
|
-
|
|
25
|
-
export interface ChangeCounts {
|
|
26
|
-
additions: number;
|
|
27
|
-
deletions: number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Changed lines that diffr folds by default count as done, the way the
|
|
32
|
-
* reader's viewed marks do. `folded` is how many of the scope's lines are
|
|
33
|
-
* done only because they are folded; `remaining` excludes them.
|
|
34
|
-
* "folded" is the state of a scope with nothing left to read and nothing the
|
|
35
|
-
* reader marked: all of it starts folded.
|
|
36
|
-
*/
|
|
37
|
-
export interface CoverageProgress {
|
|
38
|
-
state: "unread" | "partial" | "viewed" | "folded";
|
|
39
|
-
total: ChangeCounts;
|
|
40
|
-
remaining: ChangeCounts;
|
|
41
|
-
folded: ChangeCounts;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface CoverageFile {
|
|
45
|
-
path: string;
|
|
46
|
-
previousPath?: string;
|
|
47
|
-
fingerprint: string;
|
|
48
|
-
changed: Coverage;
|
|
49
|
-
/** The changed lines diffr folds by default: every changed line of a file
|
|
50
|
-
* it hides, or those under a region that starts collapsed. Absent without
|
|
51
|
-
* structural data, where every changed line is left to read. */
|
|
52
|
-
folded?: Coverage;
|
|
53
|
-
viewed: Coverage;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export const emptyCoverage = (): Coverage => ({ base: [], head: [] });
|
|
57
|
-
|
|
58
|
-
export function intersectIntervals(
|
|
59
|
-
left: readonly LineInterval[],
|
|
60
|
-
right: readonly LineInterval[],
|
|
61
|
-
): LineInterval[] {
|
|
62
|
-
const result: LineInterval[] = [];
|
|
63
|
-
|
|
64
|
-
const a = unionIntervals(left),
|
|
65
|
-
b = unionIntervals(right);
|
|
66
|
-
|
|
67
|
-
let i = 0,
|
|
68
|
-
j = 0;
|
|
69
|
-
|
|
70
|
-
while (i < a.length && j < b.length) {
|
|
71
|
-
const start = Math.max(a[i][0], b[j][0]),
|
|
72
|
-
end = Math.min(a[i][1], b[j][1]);
|
|
73
|
-
|
|
74
|
-
if (start < end) result.push([start, end]);
|
|
75
|
-
|
|
76
|
-
if (a[i][1] < b[j][1]) i++;
|
|
77
|
-
else j++;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return result;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function subtractIntervals(
|
|
84
|
-
left: readonly LineInterval[],
|
|
85
|
-
right: readonly LineInterval[],
|
|
86
|
-
): LineInterval[] {
|
|
87
|
-
const result: LineInterval[] = [];
|
|
88
|
-
const removed = unionIntervals(right);
|
|
89
|
-
|
|
90
|
-
for (const [start, end] of unionIntervals(left)) {
|
|
91
|
-
let cursor = start;
|
|
92
|
-
|
|
93
|
-
for (const [from, to] of removed) {
|
|
94
|
-
if (to <= cursor) continue;
|
|
95
|
-
|
|
96
|
-
if (from >= end) break;
|
|
97
|
-
|
|
98
|
-
if (from > cursor) result.push([cursor, from]);
|
|
99
|
-
cursor = Math.min(end, Math.max(cursor, to));
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (cursor < end) result.push([cursor, end]);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return result;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function updateCoverage(
|
|
109
|
-
current: Coverage,
|
|
110
|
-
scope: Coverage,
|
|
111
|
-
viewed: boolean,
|
|
112
|
-
): Coverage {
|
|
113
|
-
const apply = (side: "base" | "head") =>
|
|
114
|
-
viewed
|
|
115
|
-
? unionIntervals([...current[side], ...scope[side]])
|
|
116
|
-
: subtractIntervals(current[side], scope[side]);
|
|
117
|
-
|
|
118
|
-
return { base: apply("base"), head: apply("head") };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function scopedCoverage(
|
|
122
|
-
file: CoverageFile,
|
|
123
|
-
sources?: readonly FileLineRange[],
|
|
124
|
-
): Coverage {
|
|
125
|
-
if (!sources) return file.changed;
|
|
126
|
-
|
|
127
|
-
const side = (side: "base" | "head") =>
|
|
128
|
-
intersectIntervals(
|
|
129
|
-
file.changed[side],
|
|
130
|
-
sources.flatMap((source): LineInterval[] =>
|
|
131
|
-
source.side === side &&
|
|
132
|
-
source.file ===
|
|
133
|
-
(side === "base" ? (file.previousPath ?? file.path) : file.path)
|
|
134
|
-
? [[source.fromLine - 1, source.toLine]]
|
|
135
|
-
: [],
|
|
136
|
-
),
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
return { base: side("base"), head: side("head") };
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/** Each file's own sources, grouped once. */
|
|
143
|
-
export function sourcesForFile(
|
|
144
|
-
sources?: readonly FileLineRange[],
|
|
145
|
-
): (file: CoverageFile) => FileLineRange[] | undefined {
|
|
146
|
-
if (!sources) return () => undefined;
|
|
147
|
-
const byFile = Map.groupBy(sources, (source) => source.file);
|
|
148
|
-
|
|
149
|
-
return (file) => {
|
|
150
|
-
const base = byFile.get(file.previousPath ?? file.path) ?? [];
|
|
151
|
-
|
|
152
|
-
return file.previousPath && file.previousPath !== file.path
|
|
153
|
-
? [...base, ...(byFile.get(file.path) ?? [])]
|
|
154
|
-
: base;
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export function coverageProgress(
|
|
159
|
-
files: readonly CoverageFile[],
|
|
160
|
-
sources?: readonly FileLineRange[],
|
|
161
|
-
): CoverageProgress {
|
|
162
|
-
const total = { additions: 0, deletions: 0 },
|
|
163
|
-
remaining = { additions: 0, deletions: 0 },
|
|
164
|
-
folded = { additions: 0, deletions: 0 };
|
|
165
|
-
|
|
166
|
-
const own = sourcesForFile(sources);
|
|
167
|
-
|
|
168
|
-
for (const file of files) {
|
|
169
|
-
const scope = scopedCoverage(file, own(file));
|
|
170
|
-
const counts = structuralChangeCounts(scope);
|
|
171
|
-
|
|
172
|
-
const side = (side: "base" | "head") => {
|
|
173
|
-
const unviewed = subtractIntervals(scope[side], file.viewed[side]);
|
|
174
|
-
|
|
175
|
-
return {
|
|
176
|
-
unread: subtractIntervals(unviewed, file.folded?.[side] ?? []),
|
|
177
|
-
folded: intersectIntervals(unviewed, file.folded?.[side] ?? []),
|
|
178
|
-
};
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
const base = side("base"),
|
|
182
|
-
head = side("head");
|
|
183
|
-
|
|
184
|
-
const unread = structuralChangeCounts({
|
|
185
|
-
base: base.unread,
|
|
186
|
-
head: head.unread,
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
const foldedCounts = structuralChangeCounts({
|
|
190
|
-
base: base.folded,
|
|
191
|
-
head: head.folded,
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
total.additions += counts.added;
|
|
195
|
-
total.deletions += counts.removed;
|
|
196
|
-
remaining.additions += unread.added;
|
|
197
|
-
remaining.deletions += unread.removed;
|
|
198
|
-
folded.additions += foldedCounts.added;
|
|
199
|
-
folded.deletions += foldedCounts.removed;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return {
|
|
203
|
-
total,
|
|
204
|
-
remaining,
|
|
205
|
-
folded,
|
|
206
|
-
state: progressState(total, remaining, folded),
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/** Progress over several comparisons at once: the sums, and the same state
|
|
211
|
-
* rule as one. */
|
|
212
|
-
export function mergeCoverageProgress(
|
|
213
|
-
parts: readonly CoverageProgress[],
|
|
214
|
-
): CoverageProgress {
|
|
215
|
-
const total = { additions: 0, deletions: 0 },
|
|
216
|
-
remaining = { additions: 0, deletions: 0 },
|
|
217
|
-
folded = { additions: 0, deletions: 0 };
|
|
218
|
-
|
|
219
|
-
for (const part of parts) {
|
|
220
|
-
total.additions += part.total.additions;
|
|
221
|
-
total.deletions += part.total.deletions;
|
|
222
|
-
remaining.additions += part.remaining.additions;
|
|
223
|
-
remaining.deletions += part.remaining.deletions;
|
|
224
|
-
folded.additions += part.folded.additions;
|
|
225
|
-
folded.deletions += part.folded.deletions;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return {
|
|
229
|
-
total,
|
|
230
|
-
remaining,
|
|
231
|
-
folded,
|
|
232
|
-
state: progressState(total, remaining, folded),
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/** Done lines are the viewed and the folded ones; the state names which. */
|
|
237
|
-
function progressState(
|
|
238
|
-
total: ChangeCounts,
|
|
239
|
-
remaining: ChangeCounts,
|
|
240
|
-
folded: ChangeCounts,
|
|
241
|
-
): CoverageProgress["state"] {
|
|
242
|
-
const size = total.additions + total.deletions,
|
|
243
|
-
unread = remaining.additions + remaining.deletions,
|
|
244
|
-
viewed = size - unread - folded.additions - folded.deletions;
|
|
245
|
-
|
|
246
|
-
if (size > 0 && unread === 0) return viewed > 0 ? "viewed" : "folded";
|
|
247
|
-
|
|
248
|
-
return viewed > 0 ? "partial" : "unread";
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
export function coverageSources(
|
|
252
|
-
file: CoverageFile,
|
|
253
|
-
coverage = file.viewed,
|
|
254
|
-
): FileLineRange[] {
|
|
255
|
-
return (["base", "head"] as const).flatMap((side) =>
|
|
256
|
-
coverage[side].map(([start, end]) => ({
|
|
257
|
-
side,
|
|
258
|
-
file: side === "base" ? (file.previousPath ?? file.path) : file.path,
|
|
259
|
-
fromLine: start + 1,
|
|
260
|
-
toLine: end,
|
|
261
|
-
})),
|
|
262
|
-
);
|
|
263
|
-
}
|
package/dist/profile-BstQkIY0.js
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type FileLineRange,
|
|
3
|
-
type Lens,
|
|
4
|
-
type LensSource,
|
|
5
|
-
anchorSelection,
|
|
6
|
-
} from "@dev.fast/whiteboard-document";
|
|
7
|
-
import {
|
|
8
|
-
type CoverageFile,
|
|
9
|
-
coverageSources,
|
|
10
|
-
scopedCoverage,
|
|
11
|
-
sourcesForFile,
|
|
12
|
-
subtractIntervals,
|
|
13
|
-
unionIntervals,
|
|
14
|
-
} from "@review/viewed-coverage.js";
|
|
15
|
-
import { Minimatch } from "minimatch";
|
|
16
|
-
|
|
17
|
-
/** Subtract authored coverage, independently of viewed state. */
|
|
18
|
-
export function uncategorizedSources(
|
|
19
|
-
files: readonly CoverageFile[],
|
|
20
|
-
sources: readonly FileLineRange[],
|
|
21
|
-
): FileLineRange[] {
|
|
22
|
-
const own = sourcesForFile(sources);
|
|
23
|
-
|
|
24
|
-
return files.flatMap((file) => {
|
|
25
|
-
const covered = scopedCoverage(file, own(file));
|
|
26
|
-
|
|
27
|
-
return coverageSources(file, {
|
|
28
|
-
base: subtractIntervals(file.changed.base, covered.base),
|
|
29
|
-
head: subtractIntervals(file.changed.head, covered.head),
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Resolve all targets into one union; a whole-file range subsumes narrower ranges. */
|
|
35
|
-
export function resolveFileLens(
|
|
36
|
-
lens: Lens,
|
|
37
|
-
files: readonly CoverageFile[],
|
|
38
|
-
fileSources: ReadonlyMap<string, FileLineRange[]>,
|
|
39
|
-
resolve: (source: LensSource) => FileLineRange[],
|
|
40
|
-
) {
|
|
41
|
-
const targets = lens.targets;
|
|
42
|
-
|
|
43
|
-
const selected = targets.flatMap((target) => {
|
|
44
|
-
if (target.kind === "ranges")
|
|
45
|
-
return target.sources.flatMap((source) =>
|
|
46
|
-
resolve(anchorSelection(source)),
|
|
47
|
-
);
|
|
48
|
-
const matches = fileLensMatcher(target.patterns);
|
|
49
|
-
|
|
50
|
-
return files
|
|
51
|
-
.filter(matches)
|
|
52
|
-
.flatMap((file) => fileSources.get(file.path) ?? []);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const groups = new Map<string, FileLineRange[]>();
|
|
56
|
-
|
|
57
|
-
for (const source of selected) {
|
|
58
|
-
const key = JSON.stringify([source.side, source.file]);
|
|
59
|
-
const group = groups.get(key) ?? [];
|
|
60
|
-
group.push(source);
|
|
61
|
-
groups.set(key, group);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const sources = [...groups.values()].flatMap((group) =>
|
|
65
|
-
unionIntervals(
|
|
66
|
-
group.map((source) => [source.fromLine - 1, source.toLine]),
|
|
67
|
-
).map(([start, end]) => ({
|
|
68
|
-
...group[0],
|
|
69
|
-
fromLine: start + 1,
|
|
70
|
-
toLine: end,
|
|
71
|
-
})),
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
const fileCount = new Set(sources.map(changedPath(files))).size;
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
sources,
|
|
78
|
-
fileCount,
|
|
79
|
-
wholeFiles: targets.every((target) => target.kind === "files"),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** The changed file a source names on its side, or the source's own file. */
|
|
84
|
-
export function changedPath(
|
|
85
|
-
files: readonly CoverageFile[],
|
|
86
|
-
): (source: FileLineRange) => string {
|
|
87
|
-
const paths = new Map<string, string>();
|
|
88
|
-
|
|
89
|
-
for (const file of files)
|
|
90
|
-
for (const key of [
|
|
91
|
-
`base:${file.previousPath ?? file.path}`,
|
|
92
|
-
`head:${file.path}`,
|
|
93
|
-
])
|
|
94
|
-
if (!paths.has(key)) paths.set(key, file.path);
|
|
95
|
-
|
|
96
|
-
return (source) => paths.get(`${source.side}:${source.file}`) ?? source.file;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/** Evaluate authored patterns against the changed-file list, never the filesystem. */
|
|
100
|
-
export function fileLensMatcher(
|
|
101
|
-
patterns: readonly string[],
|
|
102
|
-
): (file: { path: string; previousPath?: string }) => boolean {
|
|
103
|
-
const matchers = patterns.map((pattern) => {
|
|
104
|
-
const normalized = pattern.startsWith("./") ? pattern.slice(2) : pattern;
|
|
105
|
-
|
|
106
|
-
const glob = new Minimatch(normalized, {
|
|
107
|
-
nocase: process.platform === "darwin" || process.platform === "win32",
|
|
108
|
-
windowsPathsNoEscape: true,
|
|
109
|
-
nonegate: true,
|
|
110
|
-
nocomment: true,
|
|
111
|
-
optimizationLevel: 2,
|
|
112
|
-
platform: "linux",
|
|
113
|
-
nocaseMagicOnly: true,
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
return (path: string) => path === normalized || glob.match(path);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
return (file) =>
|
|
120
|
-
matchers.some(
|
|
121
|
-
(matches) =>
|
|
122
|
-
matches(file.path) ||
|
|
123
|
-
(file.previousPath !== undefined && matches(file.previousPath)),
|
|
124
|
-
);
|
|
125
|
-
}
|
package/src/unified-diff.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
export interface DiffHunk {
|
|
2
|
-
file: string;
|
|
3
|
-
oldStart: number;
|
|
4
|
-
oldLines: number;
|
|
5
|
-
newStart: number;
|
|
6
|
-
newLines: number;
|
|
7
|
-
lines: DiffHunkLine[];
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface DiffHunkLine {
|
|
11
|
-
kind: "context" | "add" | "remove";
|
|
12
|
-
oldLine: number | null;
|
|
13
|
-
newLine: number | null;
|
|
14
|
-
text: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const HUNK_HEADER =
|
|
18
|
-
/^@@ -(?<oldStart>\d+)(?:,(?<oldLines>\d+))? \+(?<newStart>\d+)(?:,(?<newLines>\d+))? @@/;
|
|
19
|
-
|
|
20
|
-
export function parseUnifiedPatch(
|
|
21
|
-
file: string,
|
|
22
|
-
patch: string | null | undefined,
|
|
23
|
-
): DiffHunk[] {
|
|
24
|
-
if (!patch) return [];
|
|
25
|
-
|
|
26
|
-
const hunks: DiffHunk[] = [];
|
|
27
|
-
let current: DiffHunk | null = null;
|
|
28
|
-
let oldLine = 0;
|
|
29
|
-
let newLine = 0;
|
|
30
|
-
|
|
31
|
-
for (const row of patch.split(/\r?\n/)) {
|
|
32
|
-
const header = HUNK_HEADER.exec(row);
|
|
33
|
-
|
|
34
|
-
if (header?.groups) {
|
|
35
|
-
current = {
|
|
36
|
-
file,
|
|
37
|
-
oldStart: Number(header.groups.oldStart),
|
|
38
|
-
oldLines: Number(header.groups.oldLines ?? "1"),
|
|
39
|
-
newStart: Number(header.groups.newStart),
|
|
40
|
-
newLines: Number(header.groups.newLines ?? "1"),
|
|
41
|
-
lines: [],
|
|
42
|
-
};
|
|
43
|
-
oldLine = current.oldStart;
|
|
44
|
-
newLine = current.newStart;
|
|
45
|
-
hunks.push(current);
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (!current || row.startsWith("\")) continue;
|
|
50
|
-
|
|
51
|
-
const marker = row[0];
|
|
52
|
-
const text = row.slice(1);
|
|
53
|
-
let line: DiffHunkLine | null = null;
|
|
54
|
-
|
|
55
|
-
if (marker === " ") {
|
|
56
|
-
line = { kind: "context", oldLine, newLine, text };
|
|
57
|
-
oldLine += 1;
|
|
58
|
-
newLine += 1;
|
|
59
|
-
} else if (marker === "+") {
|
|
60
|
-
line = { kind: "add", oldLine: null, newLine, text };
|
|
61
|
-
newLine += 1;
|
|
62
|
-
} else if (marker === "-") {
|
|
63
|
-
line = { kind: "remove", oldLine, newLine: null, text };
|
|
64
|
-
oldLine += 1;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (line) current.lines.push(line);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return hunks;
|
|
71
|
-
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as jsonNumber, c as jsonString, o as jsonObject, r as jsonArray, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
|
-
import { S as sessionMetaSchema, b as commitShaSchema, y as byCommitSchema } from "./src-CGP5ytbV.js";
|
|
3
2
|
import { i as isS3MockMode, l as s3CacheIdentity, s as resolveS3Credentials, u as s3MockRoot } from "./s3-config-CjcLyFV5.js";
|
|
4
3
|
import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
4
|
+
import { S as sessionMetaSchema, b as commitShaSchema, y as byCommitSchema } from "./src-CGP5ytbV.js";
|
|
5
5
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { tmpdir } from "node:os";
|