@dev.fast/whiteboard 0.5.1 → 0.5.2-preview.20261104.147
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-Bw3PT3Qo.js → account-alias-DXpd0Px8.js} +5 -5
- package/dist/{agent-cli-kHRrwO4n.js → agent-cli-COrZtFks.js} +9 -9
- package/dist/agent-cli-x6-Eh1S-.js +2 -0
- package/dist/{agent-client-CMacGbMp.js → agent-client-BFtYm3Ng.js} +4 -4
- package/dist/{authoring-tools-CiLy46kh.js → authoring-tools-D1avYp8-.js} +12 -8
- package/dist/{background-server-eZWXoVcI.js → background-server-BiRSqjxG.js} +4 -4
- package/dist/{background-server-BLNHbksB.js → background-server-HOJozY99.js} +1 -1
- package/dist/build-info.json +1 -1
- package/dist/{cli-Bxmiqutp.js → cli-CSlwGRvH.js} +1 -1
- package/dist/{cli-runner-DQPuu7kJ.js → cli-runner-CuffXA0Q.js} +22 -22
- package/dist/cli.js +2 -2
- package/dist/{fuzzy-match-DZjeOaPY.js → fuzzy-match-DEo941za.js} +3 -3
- package/dist/{headless-host-B4r0s1ks.js → headless-host-BCkXVVpU.js} +1 -1
- package/dist/{headless-host-Dl2KZ9IT.js → headless-host-CIuJJjmM.js} +561 -415
- package/dist/{import-YAIU6rB0.js → import-CjcW7EIQ.js} +235 -63
- package/dist/{local-data-C58vzLZR.js → local-data-B5PBZ0Ge.js} +101 -17
- package/dist/{mcp-COYWiGVn.js → mcp-Ba3WvhUh.js} +9 -6
- package/dist/{package-paths-Cg6fnaGp.js → package-paths-Dk7MOXxN.js} +1 -1
- package/dist/profile-BstQkIY0.js +2 -0
- package/dist/{profile--BYIjPkc.js → profile-CNMhLUhf.js} +2 -2
- package/dist/{remote-attach-C1prLjmj.js → remote-attach-DkZoYBHV.js} +4 -4
- package/dist/{remote-extensions-Bw029iIS.js → remote-extensions-BvV29_gk.js} +1 -1
- package/dist/{remote-extensions-MUUgbLJn.js → remote-extensions-L95HNwIH.js} +2 -2
- package/dist/{remote-language-server-z3rdHcLL.js → remote-language-server-l4ConTfj.js} +4 -4
- package/dist/{remote-uninstall-B3Slwor1.js → remote-uninstall-BAQM7cU8.js} +5 -5
- package/dist/{request-origin-B3_XI2VA.js → request-origin-DZexKlc4.js} +28 -5
- package/dist/{review-app-launcher-BZEbDKuK.js → review-app-launcher-B5F10y_4.js} +2 -2
- package/dist/{review-home-paths-LdGS4SpR.js → review-home-paths-BmZX2qiz.js} +1 -1
- package/dist/{review-telemetry-x8u-9EZb.js → review-telemetry-kQ7esDRE.js} +4 -4
- package/dist/server/desktop-host.js +26 -38
- package/dist/{server-discovery-WmuFl2S3.js → server-discovery-DYY_xeG9.js} +2 -2
- package/dist/sharing/index.d.ts +137 -14
- package/dist/sharing/index.js +1 -1
- package/dist/{src-DLWol7GZ.js → src-B-91Rd2d.js} +17 -1
- package/dist/{src-B2b8cCoI.js → src-DirPN_Qh.js} +82 -6
- package/dist/{stored-document-migration-iwIQ4l5G.js → stored-document-migration-vg0NAzXG.js} +4 -89
- package/dist/{thread-state-B7L1mpN_.js → thread-state-Jxoh1hde.js} +1 -1
- package/dist/{tool-failure-RLR8m9hq.js → tool-failure-BLBwcl3H.js} +319 -55
- package/instructions/animation.md +69 -5
- package/instructions/animations/before-after-structure/README.md +27 -0
- package/instructions/animations/before-after-structure/animation.html +89 -0
- package/instructions/animations/before-after-structure/block.json +10 -0
- package/instructions/animations/before-after-structure/frames.json +313 -0
- package/instructions/animations/cache-fill-evict/README.md +24 -0
- package/instructions/animations/cache-fill-evict/animation.html +81 -0
- package/instructions/animations/cache-fill-evict/block.json +13 -0
- package/instructions/animations/cache-fill-evict/frames.json +79 -0
- package/instructions/animations/cache-fill-evict/scenarios.json +17 -0
- package/instructions/animations/log-replay/README.md +25 -0
- package/instructions/animations/log-replay/animation.html +86 -0
- package/instructions/animations/log-replay/block.json +10 -0
- package/instructions/animations/log-replay/frames.json +143 -0
- package/instructions/animations/log-replay/scenarios.json +18 -0
- package/instructions/animations/queue-workers/README.md +23 -0
- package/instructions/animations/queue-workers/animation.html +107 -0
- package/instructions/animations/queue-workers/block.json +13 -0
- package/instructions/animations/queue-workers/frames.json +119 -0
- package/instructions/animations/queue-workers/scenarios.json +18 -0
- package/instructions/animations/race-two-lanes/README.md +22 -0
- package/instructions/animations/race-two-lanes/animation.html +97 -0
- package/instructions/animations/race-two-lanes/block.json +1 -0
- package/instructions/animations/race-two-lanes/frames.json +234 -0
- package/instructions/animations/race-two-lanes/scenarios.json +19 -0
- package/instructions/animations/request-across-layers/README.md +24 -0
- package/instructions/animations/request-across-layers/animation.html +85 -0
- package/instructions/animations/request-across-layers/block.json +17 -0
- package/instructions/animations/request-across-layers/frames.json +58 -0
- package/instructions/animations/request-across-layers/scenarios.json +12 -0
- package/instructions/animations/request-timing/README.md +22 -0
- package/instructions/animations/request-timing/animation.html +120 -0
- package/instructions/animations/request-timing/block.json +21 -0
- package/instructions/animations/request-timing/markers.json +32 -0
- package/instructions/animations/request-timing/scenarios.json +4 -0
- package/instructions/animations/retry-backoff/README.md +22 -0
- package/instructions/animations/retry-backoff/animation.html +122 -0
- package/instructions/animations/retry-backoff/block.json +10 -0
- package/instructions/animations/retry-backoff/frames.json +65 -0
- package/instructions/animations/retry-backoff/scenarios.json +12 -0
- package/instructions/animations/state-machine/README.md +24 -0
- package/instructions/animations/state-machine/animation.html +95 -0
- package/instructions/animations/state-machine/block.json +9 -0
- package/instructions/animations/state-machine/frames.json +79 -0
- package/instructions/animations/state-machine/scenarios.json +12 -0
- package/instructions/animations/video-platform-architecture/README.md +24 -0
- package/instructions/animations/video-platform-architecture/animation.html +76 -0
- package/instructions/animations/video-platform-architecture/block.json +17 -0
- package/instructions/animations/video-platform-architecture/frames.json +97 -0
- package/instructions/animations/video-platform-architecture/scenarios.json +28 -0
- package/instructions/whiteboard.d.ts +168 -14
- package/package.json +5 -5
- package/src/animation-stage-kit.ts +150 -10
- package/src/cli-runner.ts +4 -1
- package/src/fixtures/blocks/clip.json +19 -0
- package/src/review-api/README.md +1 -0
- package/src/review-api/agent-cli.ts +3 -2
- package/src/review-api/animation-drafts.ts +151 -47
- package/src/review-api/animation-references.ts +92 -0
- package/src/review-api/animation-render.ts +106 -0
- package/src/review-api/authoring-tools.ts +10 -3
- package/src/review-api/comparison-coverage.ts +6 -7
- package/src/review-api/document-text.ts +27 -12
- package/src/review-api/http.ts +52 -6
- package/src/review-api/instructions.ts +1 -1
- package/src/review-api/mcp.ts +10 -5
- package/src/review-api/public-tools.ts +71 -2
- package/src/review-api/review-progress.ts +2 -3
- package/src/review-api/store.ts +89 -12
- package/src/server/desktop-server.ts +17 -5
- package/src/server/headless-host.ts +4 -0
- package/src/server/review-gateway.ts +1 -0
- package/src/server/review-server-core.ts +71 -12
- package/src/sharing/client.ts +129 -32
- package/src/sharing/export.ts +42 -5
- package/src/sharing/file.ts +8 -0
- package/src/sharing/host.ts +202 -73
- package/src/sharing/import.ts +125 -33
- package/src/ui-telemetry-events.ts +26 -1
- package/dist/agent-cli-B8KBHuh_.js +0 -2
- package/dist/profile-BjcXi-oH.js +0 -2
- package/src/review-api/lens-alignment.ts +0 -52
package/src/sharing/import.ts
CHANGED
|
@@ -21,7 +21,10 @@ import {
|
|
|
21
21
|
import { textIncludesQuote } from "@review/evidence.js";
|
|
22
22
|
import type { LocalReviewData } from "@review/review-api/local-data.js";
|
|
23
23
|
import { pullRequestUrl } from "@review/review-api/origin.js";
|
|
24
|
-
import type {
|
|
24
|
+
import type {
|
|
25
|
+
ReviewStore,
|
|
26
|
+
SharedProvenance,
|
|
27
|
+
} from "@review/review-api/store.js";
|
|
25
28
|
import { traceSchema } from "@review/review-api/trace-schema.js";
|
|
26
29
|
import {
|
|
27
30
|
devReviewHome,
|
|
@@ -45,7 +48,7 @@ import {
|
|
|
45
48
|
sharedGit,
|
|
46
49
|
} from "./repository.js";
|
|
47
50
|
|
|
48
|
-
export const sharedSnapshotSchema = z.
|
|
51
|
+
export const sharedSnapshotSchema = z.object({
|
|
49
52
|
reviewId: z.string().min(1),
|
|
50
53
|
version: z.number().int().nonnegative(),
|
|
51
54
|
/** Empty for a board never named; it reads "Untitled". */
|
|
@@ -60,7 +63,7 @@ export const sharedSnapshotSchema = z.strictObject({
|
|
|
60
63
|
lenses: z.array(lensSchema).optional(),
|
|
61
64
|
createdAt: z.string(),
|
|
62
65
|
origin: z
|
|
63
|
-
.
|
|
66
|
+
.object({
|
|
64
67
|
branch: z.string().optional(),
|
|
65
68
|
baseRef: z.string().optional(),
|
|
66
69
|
baseBranch: z.string().optional(),
|
|
@@ -75,7 +78,7 @@ export const sharedSnapshotSchema = z.strictObject({
|
|
|
75
78
|
|
|
76
79
|
const count = z.number().int().nonnegative();
|
|
77
80
|
|
|
78
|
-
const counts = z.
|
|
81
|
+
const counts = z.object({ additions: count, deletions: count });
|
|
79
82
|
|
|
80
83
|
const mapSchema = softwareModelDataSchema.extend({
|
|
81
84
|
commit: z.string().regex(COMMIT_ID),
|
|
@@ -88,10 +91,10 @@ const mapSchema = softwareModelDataSchema.extend({
|
|
|
88
91
|
counts.extend({
|
|
89
92
|
file: z.string(),
|
|
90
93
|
hunks: z.array(
|
|
91
|
-
z.
|
|
94
|
+
z.object({
|
|
92
95
|
startLine: count,
|
|
93
96
|
lines: z.array(
|
|
94
|
-
z.
|
|
97
|
+
z.object({
|
|
95
98
|
kind: z.enum(["add", "remove"]),
|
|
96
99
|
oldLine: count.nullable(),
|
|
97
100
|
newLine: count.nullable(),
|
|
@@ -106,7 +109,7 @@ const mapSchema = softwareModelDataSchema.extend({
|
|
|
106
109
|
),
|
|
107
110
|
});
|
|
108
111
|
|
|
109
|
-
export const sharePresentationSchema = z.
|
|
112
|
+
export const sharePresentationSchema = z.object({
|
|
110
113
|
maps: z.record(z.string(), mapSchema),
|
|
111
114
|
});
|
|
112
115
|
|
|
@@ -129,6 +132,12 @@ export function needsRepository(
|
|
|
129
132
|
|
|
130
133
|
export function validateShareBundle(input: ShareBundle) {
|
|
131
134
|
const bundle = shareBundleSchema.parse(input);
|
|
135
|
+
|
|
136
|
+
if (bundle.frozen)
|
|
137
|
+
throw new ReviewInputError(
|
|
138
|
+
"This whiteboard is a read-only snapshot of uncommitted changes. View it in the browser.",
|
|
139
|
+
409,
|
|
140
|
+
);
|
|
132
141
|
// SAFETY: a bundle is parsed from JSON, so its snapshot is a JSON object.
|
|
133
142
|
const stored = bundle.snapshot as JsonObject;
|
|
134
143
|
|
|
@@ -235,18 +244,99 @@ export interface ShareImport {
|
|
|
235
244
|
onStage?: (stage: "fetching" | "validating") => void;
|
|
236
245
|
}
|
|
237
246
|
|
|
238
|
-
|
|
239
|
-
|
|
247
|
+
export const FRESH_IMPORT_VERSION = 0;
|
|
248
|
+
|
|
249
|
+
/** The revision a link serves and its share's latest. */
|
|
250
|
+
export interface ServedRevision {
|
|
251
|
+
revision: { id: string; version: number; createdAt: number };
|
|
252
|
+
latest: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export type ShareCopyPlan =
|
|
256
|
+
| { kind: "open"; reviewId: string }
|
|
257
|
+
| { kind: "refresh"; reviewId: string; version: number }
|
|
258
|
+
| { kind: "import" };
|
|
259
|
+
|
|
260
|
+
/** Which copy a served revision opens or refreshes in place; otherwise a new copy. */
|
|
261
|
+
export function planShareCopy(
|
|
262
|
+
copies: ReturnType<ReviewStore["copiesOf"]>,
|
|
263
|
+
served: ServedRevision,
|
|
264
|
+
pinned = false,
|
|
265
|
+
): ShareCopyPlan {
|
|
266
|
+
const same = copies.find(({ shared }) =>
|
|
267
|
+
shared.revisionId === undefined
|
|
268
|
+
? shared.sharedAt === served.revision.createdAt
|
|
269
|
+
: shared.revisionId === served.revision.id,
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
if (same) return { kind: "open", reviewId: same.reviewId };
|
|
273
|
+
|
|
274
|
+
const unedited =
|
|
275
|
+
!pinned &&
|
|
276
|
+
served.revision.id === served.latest &&
|
|
277
|
+
copies.find(
|
|
278
|
+
(copy) =>
|
|
279
|
+
!copy.shared.pinned &&
|
|
280
|
+
copy.version === (copy.shared.importedVersion ?? FRESH_IMPORT_VERSION),
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
return unedited
|
|
284
|
+
? {
|
|
285
|
+
kind: "refresh",
|
|
286
|
+
reviewId: unedited.reviewId,
|
|
287
|
+
version: unedited.version,
|
|
288
|
+
}
|
|
289
|
+
: { kind: "import" };
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/** Opens, refreshes or copies a link's board by the revision it serves. */
|
|
293
|
+
export async function receiveShare(
|
|
294
|
+
input: ShareImport,
|
|
295
|
+
key: string,
|
|
296
|
+
served: ServedRevision,
|
|
297
|
+
download: () => Promise<{
|
|
298
|
+
bundle: ShareBundle;
|
|
299
|
+
attribution: ShareAttribution;
|
|
300
|
+
}>,
|
|
301
|
+
pinned = false,
|
|
302
|
+
): Promise<string> {
|
|
303
|
+
const plan = planShareCopy(input.store.copiesOf(key), served, pinned);
|
|
304
|
+
|
|
305
|
+
if (plan.kind === "open") return plan.reviewId;
|
|
306
|
+
const { bundle, attribution } = await download();
|
|
307
|
+
|
|
308
|
+
const provenance = {
|
|
309
|
+
...attribution,
|
|
310
|
+
revisionId: served.revision.id,
|
|
311
|
+
...(pinned && { pinned }),
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
if (plan.kind === "import")
|
|
315
|
+
return importShare(input, key, bundle, provenance);
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
return await importShare(input, key, bundle, provenance, plan);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
// The board was edited or deleted since the plan read it.
|
|
321
|
+
if (
|
|
322
|
+
error instanceof ReviewInputError &&
|
|
323
|
+
(error.status === 409 || error.status === 404)
|
|
324
|
+
)
|
|
325
|
+
return importShare(input, key, bundle, provenance);
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Imports a share as an ordinary board, or into a copy of its link. */
|
|
240
331
|
export async function importShare(
|
|
241
332
|
input: ShareImport,
|
|
242
333
|
key: string,
|
|
243
334
|
received: ShareBundle,
|
|
244
|
-
|
|
335
|
+
provenance?: ShareAttribution &
|
|
336
|
+
Pick<SharedProvenance, "revisionId" | "pinned">,
|
|
337
|
+
into?: { reviewId: string; version: number },
|
|
245
338
|
): Promise<string> {
|
|
246
339
|
const { store, data } = input;
|
|
247
|
-
const existing = store.copyOf(key);
|
|
248
|
-
|
|
249
|
-
if (existing) return existing;
|
|
250
340
|
const { bundle, snapshot, maps } = validateShareBundle(received);
|
|
251
341
|
const cloneUrl = bundle.repository?.cloneUrl;
|
|
252
342
|
let repositoryId: string | undefined;
|
|
@@ -319,27 +409,29 @@ export async function importShare(
|
|
|
319
409
|
|
|
320
410
|
for (const [id, copy] of ids) document = document.replaceAll(id, copy);
|
|
321
411
|
|
|
322
|
-
const
|
|
323
|
-
{
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
...
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}),
|
|
332
|
-
},
|
|
412
|
+
const create = {
|
|
413
|
+
operation: {
|
|
414
|
+
type: "create",
|
|
415
|
+
...(snapshot.title && { title: snapshot.title }),
|
|
416
|
+
...(pins
|
|
417
|
+
? { target: { kind: "commits", ...pins } }
|
|
418
|
+
: repositoryId && {
|
|
419
|
+
target: { kind: "project", repositoryId },
|
|
420
|
+
}),
|
|
333
421
|
},
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
},
|
|
341
|
-
|
|
342
|
-
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
const seed = {
|
|
425
|
+
document: JSON.parse(document),
|
|
426
|
+
lenses: snapshot.lenses,
|
|
427
|
+
origin: snapshot.origin,
|
|
428
|
+
shared: { ...provenance, cloneUrl, key },
|
|
429
|
+
copiedFrom: snapshot.reviewId,
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const { reviewId } = into
|
|
433
|
+
? await store.refreshCopy(into.reviewId, into.version, create, seed)
|
|
434
|
+
: await store.execute(create, seed, { kind: "person" });
|
|
343
435
|
|
|
344
436
|
return reviewId;
|
|
345
437
|
}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
REVIEW_COLOR_THEME_KINDS,
|
|
22
22
|
REVIEW_DIFF_LAYOUTS,
|
|
23
23
|
REVIEW_DIFF_LAYOUT_SCOPES,
|
|
24
|
+
REVIEW_OPEN_FILES_IN_CHOICES,
|
|
24
25
|
isJsonObject,
|
|
25
26
|
jsonBoolean,
|
|
26
27
|
jsonNumber,
|
|
@@ -93,7 +94,12 @@ export const LSP_FEATURE = [
|
|
|
93
94
|
|
|
94
95
|
export const LSP_VIA = ["command", "mouse"] as const;
|
|
95
96
|
|
|
96
|
-
export const LSP_EDITOR_KIND = [
|
|
97
|
+
export const LSP_EDITOR_KIND = [
|
|
98
|
+
"files_tab",
|
|
99
|
+
"inline_peek",
|
|
100
|
+
"diff",
|
|
101
|
+
"definition_peek",
|
|
102
|
+
] as const;
|
|
97
103
|
|
|
98
104
|
export const LSP_LANGUAGE = [
|
|
99
105
|
"typescript",
|
|
@@ -212,6 +218,17 @@ const MAP_LEVEL = ["system", "container", "component", "code"] as const;
|
|
|
212
218
|
|
|
213
219
|
const SOURCE_TREE_OPENED_VIA = ["topbar", "home"] as const;
|
|
214
220
|
|
|
221
|
+
const SOURCE_OPENED_DESTINATION = [
|
|
222
|
+
"source_window",
|
|
223
|
+
"vscode",
|
|
224
|
+
"cursor",
|
|
225
|
+
"zed",
|
|
226
|
+
"intellij",
|
|
227
|
+
"application",
|
|
228
|
+
] as const;
|
|
229
|
+
|
|
230
|
+
const SOURCE_OPENED_KIND = ["file", "diff", "references", "tree"] as const;
|
|
231
|
+
|
|
215
232
|
/** Tab names the dwell beacon reports. Shared with its request parser. */
|
|
216
233
|
export const REVIEW_TELEMETRY_TABS = [
|
|
217
234
|
"review",
|
|
@@ -431,6 +448,13 @@ export const UI_TELEMETRY_EVENTS = {
|
|
|
431
448
|
event: "review_source_tree_opened",
|
|
432
449
|
properties: { via: SOURCE_TREE_OPENED_VIA },
|
|
433
450
|
},
|
|
451
|
+
source_opened: {
|
|
452
|
+
event: "review_source_opened",
|
|
453
|
+
properties: {
|
|
454
|
+
destination: SOURCE_OPENED_DESTINATION,
|
|
455
|
+
kind: SOURCE_OPENED_KIND,
|
|
456
|
+
},
|
|
457
|
+
},
|
|
434
458
|
whiteboard_file_exported: {
|
|
435
459
|
event: "review_whiteboard_file_exported",
|
|
436
460
|
properties: {},
|
|
@@ -571,6 +595,7 @@ export const UI_TELEMETRY_EVENTS = {
|
|
|
571
595
|
setting: SETTING_NAME,
|
|
572
596
|
enabled: "boolean",
|
|
573
597
|
value: REVIEW_COLOR_THEME_KINDS,
|
|
598
|
+
choice: REVIEW_OPEN_FILES_IN_CHOICES,
|
|
574
599
|
},
|
|
575
600
|
},
|
|
576
601
|
review_opened: {
|
package/dist/profile-BjcXi-oH.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { AlignmentRow } from "@dev.fast/whiteboard-document";
|
|
2
|
-
import { parseUnifiedPatch } from "@review/unified-diff.js";
|
|
3
|
-
|
|
4
|
-
/** Project the already-computed patch's runs, including unchanged gaps. */
|
|
5
|
-
export function textualRows(
|
|
6
|
-
path: string,
|
|
7
|
-
patch: string,
|
|
8
|
-
baseCount: number,
|
|
9
|
-
headCount: number,
|
|
10
|
-
): AlignmentRow[] {
|
|
11
|
-
const rows: AlignmentRow[] = [];
|
|
12
|
-
|
|
13
|
-
let base = 0,
|
|
14
|
-
head = 0;
|
|
15
|
-
|
|
16
|
-
const append = (baseEnd: number, headEnd: number) => {
|
|
17
|
-
while (base < baseEnd || head < headEnd)
|
|
18
|
-
rows.push([
|
|
19
|
-
base < baseEnd ? base++ : null,
|
|
20
|
-
head < headEnd ? head++ : null,
|
|
21
|
-
]);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
for (const hunk of parseUnifiedPatch(path, patch)) {
|
|
25
|
-
append(
|
|
26
|
-
hunk.oldLines ? hunk.oldStart - 1 : hunk.oldStart,
|
|
27
|
-
hunk.newLines ? hunk.newStart - 1 : hunk.newStart,
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
let removed = 0,
|
|
31
|
-
added = 0;
|
|
32
|
-
|
|
33
|
-
const flush = () => {
|
|
34
|
-
append(base + removed, head + added);
|
|
35
|
-
removed = added = 0;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
for (const line of hunk.lines) {
|
|
39
|
-
if (line.kind === "context") {
|
|
40
|
-
flush();
|
|
41
|
-
append(base + 1, head + 1);
|
|
42
|
-
} else if (line.kind === "add") added++;
|
|
43
|
-
else removed++;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
flush();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
append(baseCount, headCount);
|
|
50
|
-
|
|
51
|
-
return rows;
|
|
52
|
-
}
|