@tanishqkancharla/diffmap 0.3.0 → 0.6.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/README.md CHANGED
@@ -75,16 +75,56 @@ import {
75
75
  | Fence info string | Viewer |
76
76
  | ---------------------------------------------- | ------------------------------------------------------------------------------------------------- |
77
77
  | `mermaid` | Beautiful Mermaid |
78
+ | `services` | Animated service diagram you can play or step through |
79
+ | `mermaid diff` or `services diff` | The same diagram with [added and removed parts marked](#diagram-diffs) |
78
80
  | `callstack` or `diff` containing `└──` / `├──` | Interactive stack rows, no file header |
79
81
  | `diff` or `diff:path` with a file path | Pierre patch with Pierre’s file header |
80
82
  | `diff` with no path | Pierre patch, no file header |
81
83
  | `changes` with a commit, range, or empty body | Files changed card with a Review button; empty means uncommitted changes |
82
84
  | `start:end:path` | Pierre file excerpt with Pierre’s file header |
83
85
  | `html` | Trusted HTML from this file. diffmap does not sanitize it. Only use it for local files you wrote. |
84
- | other langs | Maui `CodeBlock` |
86
+ | other langs | Highlighted code with optional [titles, highlights, and notes](#highlight-lines-and-add-notes) |
85
87
 
86
88
  Fences keep whitespace. Use them for mermaid, call stacks, and diffs.
87
89
 
90
+ ### Highlight lines and add notes
91
+
92
+ In a code fence, `{2,4-6}` after the language highlights those lines. Comment
93
+ lines at the bottom of the fence add notes that show on hover or keyboard focus:
94
+
95
+ ````md
96
+ ```ts {2-3}
97
+ function requestHandler(record: RecordInput) {
98
+ const error = validateInput(record);
99
+ if (error) return error;
100
+ return existingService(record);
101
+ }
102
+ // [!note validateInput] Returns an error when `name` is blank, otherwise undefined.
103
+ // [!note L3] Early return, so storage never sees an invalid record.
104
+ ```
105
+ ````
106
+
107
+ - `[!note L3]` or `[!note L3-L5]` notes a line range. Any other target is a
108
+ symbol, and the note covers every whole-word occurrence in the fence.
109
+ - Start note lines with `//`, `#`, or `--`. The viewer removes them, so line
110
+ numbers count only the code above. Backticks in a note render as code.
111
+ - A symbol that does not appear, overlapping line notes, or a line number
112
+ outside the fence is a parse error. A note line above other code stays code.
113
+
114
+ Add `[Title]` after the language to show a title above the code, as in
115
+ ` ```ts [src/request.ts] {2-3} `. Call stacks and `mermaid` fences take a
116
+ title the same way, as in ` ```mermaid diff [Request flow] `, or
117
+ `::callstack{title="Request flow"}` and `::mermaid{title="Request flow"}` in
118
+ MDC. A `services` fence uses its [start caption](#animated-service-diagrams)
119
+ instead.
120
+
121
+ Call stacks take the same highlights and notes, counting rows from the first.
122
+ Write their notes with `#`. A symbol note matches the row text you see, not
123
+ hidden references. Inside a linked row, symbol notes show on hover only; the
124
+ row itself keeps keyboard focus.
125
+
126
+ Run `npx @tanishqkancharla/diffmap fixtures/code-notes.md` for an example.
127
+
88
128
  ## MDC
89
129
 
90
130
  md4x Comark components map to the same views:
@@ -114,8 +154,13 @@ startServer
114
154
  ::html
115
155
  <aside>Note.</aside>
116
156
  ::
157
+
158
+ ::details{summary="How it works"}
159
+ Folded content: prose, lists, and any fence above.
160
+ ::
117
161
  ```
118
162
 
163
+ `::details` folds its content under the `summary` label until the reader opens it.
119
164
  `.md` and `.mdx` are both markdown. Curly braces in prose are plain text.
120
165
 
121
166
  ## Link call stacks to source changes
@@ -154,9 +199,17 @@ A `changes` fence shows a commit's files as a card. Each row shows the file name
154
199
  and +N −M. **Review** opens the Diff panel on all files; a row focuses that file.
155
200
  An empty body (or `working`) means uncommitted changes.
156
201
 
202
+ Lines after the rev list the files to review, in order. The card shows those
203
+ first and folds the rest under a dimmed **N other files** row that expands and
204
+ collapses. Review opens the Diff panel in the same order. `serve` and `share`
205
+ fail if a listed file is not changed in that commit. With no list, the card
206
+ shows every file.
207
+
157
208
  ````md
158
209
  ```changes
159
210
  a1b2c3d
211
+ src/request.ts
212
+ src/validate.ts
160
213
  ```
161
214
  ````
162
215
 
@@ -188,6 +241,123 @@ Resolution uses the workspace's TypeScript configuration and current files.
188
241
  Run `npx @tanishqkancharla/diffmap fixtures/annotations.md` for an example
189
242
  with commit references, multiple files, and unchanged context.
190
243
 
244
+ ## Animated service diagrams
245
+
246
+ A `services` fence shows services, their state, and the events they send each
247
+ other, then replays those events step by step. Readers press **Play**, step with
248
+ the arrow buttons or ← and →, or click the progress bar to jump to a step.
249
+
250
+ ````md
251
+ ```services
252
+ service Browser "login page"
253
+ state cookie = none
254
+ service API "HTTP server" [[src/api.ts]]
255
+ > Receives every request and routes it to a service.
256
+ service Auth
257
+ state attempts = 0
258
+ > Failures since the last success. Five locks the account.
259
+
260
+ start "Alice logs in"
261
+ > She is signed out.
262
+ step "The browser submits the form"
263
+ Browser -> API: POST /login
264
+ step "The API asks Auth to verify"
265
+ API -> Auth: verify(alice) [[src/api.ts#login]]
266
+ > Sends the username and the password from the form.
267
+ Auth.attempts = 1
268
+ > Counted before the check, so a crash still counts as a failure.
269
+ step "The API sets the session cookie"
270
+ API -> Browser: 200 Set-Cookie
271
+ Browser.cookie = sid=s_81f
272
+ ```
273
+ ````
274
+
275
+ - `service <Name> "label"` declares a service. Indent a `service` line under
276
+ another to nest it. Names are unique within the diagram.
277
+ - `state <key> = <value>` declares a value and its initial state. Indent it under
278
+ its service.
279
+ - `start "caption"` at column 0, before the first step, captions the whole
280
+ diagram, such as `start "Alice logs in"`. It shows above the diagram until
281
+ the reader steps, and each step's caption replaces it. A `>` line under it
282
+ can say what the initial state shows. A `services` fence takes no `[Title]`;
283
+ the start caption is its title.
284
+ - `step "caption"` starts a step at column 0. The caption is required: a
285
+ sentence that says what happens, shown under the controls. Indented lines
286
+ under it are `From -> To: label` events and `Service.key = value` updates.
287
+ Every event in a step travels at once, and the updates land when the events
288
+ arrive.
289
+ - A `>` line adds text to the line above it. Indent it further than that line;
290
+ consecutive `>` lines join.
291
+ - Under a service or state, it is a description: the name gets a dotted
292
+ underline and the text shows in a tooltip on hover or focus.
293
+ - Under `start` or a step, it explains the caption and shows under it.
294
+ - Under an event or update, it is a note for that step. Notes appear in a
295
+ column beside the diagram once the step's events land, each joined by a
296
+ line to its event label or state row.
297
+ - `%%` starts a comment line.
298
+ - Append `[[reference]]` to a `service` line or an event to link it to source.
299
+
300
+ Services must be declared before the first step, and updates may only change
301
+ declared state. [ELK](https://eclipse.dev/elk/) lays the services out left to
302
+ right, or top to bottom when that fits the column better, and routes one
303
+ connection between each pair of services that talk. A request and its reply
304
+ share that connection. Indentation is significant, so `services` has no MDC form.
305
+ See [the runnable examples](fixtures/services.md).
306
+
307
+ ## Diagram diffs
308
+
309
+ Add `diff` after `mermaid` or `services` to show a change in one diagram.
310
+ Start every line with `-` for Today only, `+` for Proposed only, or a space
311
+ for both, as in a call stack diff. Indentation starts after that column.
312
+
313
+ ````md
314
+ ```mermaid diff
315
+ flowchart LR
316
+ Client --> Handler
317
+ - Handler --> Service
318
+ + Handler --> Validate
319
+ + Validate --> Service
320
+ ```
321
+ ````
322
+
323
+ diffmap draws every line once, so both versions share one layout. Nodes,
324
+ edges, sequence participants, and messages that only Today has are red and
325
+ dashed; those only Proposed has are green. A node whose label differs between
326
+ the versions is amber and shows its Proposed label. Each version must also be
327
+ a valid diagram on its own. To relabel a node, declare it on its own line
328
+ (`- B[Old]`, `+ B[New]`) so its edges are not drawn twice. In a diff,
329
+ `%% ref edge:<index>` counts edges as drawn: within each run of changed lines,
330
+ `+` lines come before `-` lines.
331
+
332
+ ````md
333
+ ```services diff
334
+ service API
335
+ - service SessionCache
336
+ - state active = 0
337
+ + service Sessions
338
+ service Postgres
339
+ - state sessions = not used
340
+ + state sessions = 0 rows
341
+
342
+ start "Sessions move to Postgres"
343
+ -step "API caches the session"
344
+ API -> SessionCache: create(alice)
345
+ SessionCache.active = 1
346
+ +step "Sessions writes the session"
347
+ API -> Sessions: create(alice)
348
+ Sessions -> Postgres: INSERT
349
+ Postgres.sessions = 1 row
350
+ ```
351
+ ````
352
+
353
+ In a `services diff`, lines inside a `-` or `+` service or step take its
354
+ sign. Today replays the unmarked and `-` lines and Proposed the unmarked and
355
+ `+` lines, so each state row shows Today's value struck through beside
356
+ Proposed's when they differ. A `-` and a `+` declaration of the same state key
357
+ give each version its own starting value. Added and removed steps color their
358
+ segment of the progress bar, and their caption starts with **Added** or
359
+ **Removed**. See [the runnable examples](fixtures/diagram-diffs.md).
360
+
191
361
  ## Link Mermaid nodes and edges
192
362
 
193
363
  Inside a Mermaid fence, add `%% ref node:<id> [[reference]]` to link a node or
package/index.html CHANGED
@@ -48,6 +48,12 @@
48
48
  })();
49
49
  </script>
50
50
  <title>diffmap</title>
51
+ <!-- A + over a −, like a diff. -->
52
+ <link
53
+ rel="icon"
54
+ type="image/svg+xml"
55
+ href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='7' fill='%2318181b'/%3E%3Crect x='14.25' y='5.5' width='3.5' height='11' rx='1.75' fill='%233fb950'/%3E%3Crect x='10.5' y='9.25' width='11' height='3.5' rx='1.75' fill='%233fb950'/%3E%3Crect x='10.5' y='21.25' width='11' height='3.5' rx='1.75' fill='%23f85149'/%3E%3C/svg%3E"
56
+ />
51
57
  </head>
52
58
  <body>
53
59
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanishqkancharla/diffmap",
3
- "version": "0.3.0",
3
+ "version": "0.6.0",
4
4
  "description": "Serve a spec or code walkthrough as a local page",
5
5
  "license": "MIT",
6
6
  "author": "Tanishq Kancharla",
@@ -44,9 +44,10 @@
44
44
  "@pierre/diffs": "1.6.1",
45
45
  "@vitejs/plugin-react": "^6.1.1",
46
46
  "beautiful-mermaid": "^1.1.3",
47
+ "elkjs": "^0.11.1",
47
48
  "errore": "^0.14.1",
48
49
  "incur": "^0.4.20",
49
- "maui": "npm:@tanishqkancharla/maui@0.0.47",
50
+ "maui": "npm:@tanishqkancharla/maui@0.0.62",
50
51
  "md4x": "^0.0.29",
51
52
  "motion": "^13.4.0",
52
53
  "purse-styles": "^0.2.3",
@@ -26,10 +26,26 @@ export type SourceReference = FileReference | ChangesReference;
26
26
  export type SourceAnnotation = {
27
27
  text: string;
28
28
  references: SourceReference[];
29
+ /** Source panel title while selected, such as a call stack row without its tree. */
30
+ title?: string;
29
31
  };
30
32
 
31
33
  export function parseCallStack(source: string): SourceAnnotation[] {
32
- return source.split("\n").map(parseAnnotation);
34
+ return source.split("\n").map((line) => {
35
+ const annotation = parseAnnotation(line);
36
+ return {
37
+ ...annotation,
38
+ title: callStackRow(annotation.text).description.trim(),
39
+ };
40
+ });
41
+ }
42
+
43
+ /** A call stack row's change mark, tree prefix, and the call it describes. */
44
+ export function callStackRow(text: string) {
45
+ const sign = text.startsWith("+") ? "+" : text.startsWith("-") ? "-" : " ";
46
+ const label = text.replace(/^[+ -]/, "");
47
+ const tree = /^[ \t│┃├└─]*/u.exec(label)![0];
48
+ return { sign, tree, description: label.slice(tree.length) };
33
49
  }
34
50
 
35
51
  export function parseAnnotation(line: string): SourceAnnotation {
package/src/changes.ts CHANGED
@@ -156,6 +156,21 @@ export type Changes = {
156
156
  files: ChangedFile[];
157
157
  };
158
158
 
159
+ /**
160
+ * Splits files into the ones to review, in `review` order, and the rest in
161
+ * their original order. An empty `review` means every file is to be reviewed.
162
+ */
163
+ export function orderForReview(files: ChangedFile[], review: string[]) {
164
+ if (review.length === 0) return { reviewed: files, other: [] };
165
+ const reviewed = review.flatMap(
166
+ (path) => files.find((file) => file.path === path) ?? [],
167
+ );
168
+ return {
169
+ reviewed,
170
+ other: files.filter((file) => !reviewed.includes(file)),
171
+ };
172
+ }
173
+
159
174
  /** Gist file holding the changes a shared spec references, keyed by rev. */
160
175
  export const GIST_CHANGES_FILE = "diffmap-changes.json";
161
176
 
@@ -0,0 +1,123 @@
1
+ export type CodeNote = {
2
+ target:
3
+ | { kind: "lines"; start: number; end: number }
4
+ | { kind: "symbol"; symbol: string };
5
+ text: string;
6
+ };
7
+
8
+ /** A symbol note's match on one line: `[start, end)` columns. */
9
+ export type SymbolMatch = { start: number; end: number; note: CodeNote };
10
+
11
+ const notePrefix = /^\s*(?:\/\/|#|--)\s*\[!note\b/;
12
+ const notePattern = /^\s*(?:\/\/|#|--)\s*\[!note\s+([^\]]+?)\s*\]\s*(.*?)\s*$/;
13
+ const linesPattern = /^L(\d+)(?:-L(\d+))?$/;
14
+ const identifierChar = /[\w$]/;
15
+
16
+ /**
17
+ * Splits trailing `// [!note target] text` lines off a code fence. Blank
18
+ * lines between notes are allowed; note-like lines above other code stay
19
+ * code, so fences that document this syntax render unchanged.
20
+ */
21
+ export function parseCodeNotes(source: string) {
22
+ const lines = source.split("\n");
23
+ let end = lines.length;
24
+ while (
25
+ end > 0 &&
26
+ (lines[end - 1]!.trim() === "" || notePrefix.test(lines[end - 1]!))
27
+ )
28
+ end--;
29
+ const notes = lines.slice(end).flatMap((line) => {
30
+ if (line.trim() === "") return [];
31
+ const match = notePattern.exec(line);
32
+ if (match === null || match[2] === "")
33
+ return [{ target: { kind: "symbol", symbol: "" }, text: line } as const];
34
+ const lineRange = linesPattern.exec(match[1]!);
35
+ const target: CodeNote["target"] =
36
+ lineRange === null
37
+ ? { kind: "symbol", symbol: match[1]! }
38
+ : {
39
+ kind: "lines",
40
+ start: Number(lineRange[1]),
41
+ end: Number(lineRange[2] ?? lineRange[1]),
42
+ };
43
+ return [{ target, text: match[2]! }];
44
+ });
45
+ return { code: lines.slice(0, end).join("\n"), notes };
46
+ }
47
+
48
+ /** Why a fence's highlights or notes are invalid, or undefined. `lines` is the rendered text of each line or row. */
49
+ export function notesProblem(fence: {
50
+ lines: string[];
51
+ highlights: number[];
52
+ notes: CodeNote[];
53
+ }) {
54
+ const lines = fence.lines;
55
+ const highlight = fence.highlights.find((n) => n < 1 || n > lines.length);
56
+ if (highlight !== undefined)
57
+ return `Highlighted line ${highlight} is outside the ${lines.length}-line code fence`;
58
+ const covered = new Set<number>();
59
+ for (const note of fence.notes) {
60
+ const target = note.target;
61
+ if (target.kind === "symbol") {
62
+ if (target.symbol === "")
63
+ return `Invalid note "${note.text.trim()}". Use // [!note symbol] text or // [!note L3-L5] text`;
64
+ if (!lines.some((line) => symbolMatches(line, target.symbol).length > 0))
65
+ return `Note target "${target.symbol}" does not appear in its code fence`;
66
+ continue;
67
+ }
68
+ if (
69
+ target.start < 1 ||
70
+ target.end < target.start ||
71
+ target.end > lines.length
72
+ )
73
+ return `Note lines L${target.start}-L${target.end} are outside the ${lines.length}-line code fence`;
74
+ for (let n = target.start; n <= target.end; n++) {
75
+ if (covered.has(n)) return `Line notes overlap at line ${n}`;
76
+ covered.add(n);
77
+ }
78
+ }
79
+ return undefined;
80
+ }
81
+
82
+ /** Non-overlapping symbol note matches on one line, left to right. */
83
+ export function lineSymbolMatches(line: string, notes: CodeNote[]) {
84
+ const matches = notes
85
+ .flatMap((note) =>
86
+ note.target.kind === "symbol"
87
+ ? symbolMatches(line, note.target.symbol).map((start) => ({
88
+ start,
89
+ end:
90
+ start +
91
+ (note.target.kind === "symbol" ? note.target.symbol.length : 0),
92
+ note,
93
+ }))
94
+ : [],
95
+ )
96
+ .toSorted((a, b) => a.start - b.start || b.end - a.end);
97
+ const kept: SymbolMatch[] = [];
98
+ for (const match of matches) {
99
+ const last = kept.at(-1);
100
+ if (last === undefined || match.start >= last.end) kept.push(match);
101
+ }
102
+ return kept;
103
+ }
104
+
105
+ /** Start columns of `symbol` in `line`, as a whole word where it starts or ends with an identifier character. */
106
+ function symbolMatches(line: string, symbol: string) {
107
+ const starts: number[] = [];
108
+ for (
109
+ let at = line.indexOf(symbol);
110
+ at !== -1;
111
+ at = line.indexOf(symbol, at + 1)
112
+ ) {
113
+ const before = line[at - 1];
114
+ const after = line[at + symbol.length];
115
+ const wordStart = identifierChar.test(symbol[0]!);
116
+ const wordEnd = identifierChar.test(symbol.at(-1)!);
117
+ if (wordStart && before !== undefined && identifierChar.test(before))
118
+ continue;
119
+ if (wordEnd && after !== undefined && identifierChar.test(after)) continue;
120
+ starts.push(at);
121
+ }
122
+ return starts;
123
+ }
package/src/errors.ts CHANGED
@@ -20,6 +20,11 @@ export class DiffmapMermaidError extends errore.createTaggedError({
20
20
  message: "diffmap could not parse mermaid in $path ($where): $reason",
21
21
  }) {}
22
22
 
23
+ export class DiffmapServicesError extends errore.createTaggedError({
24
+ name: "DiffmapServicesError",
25
+ message: "diffmap could not parse services in $path ($where): $reason",
26
+ }) {}
27
+
23
28
  export class DiffmapParseError extends errore.createTaggedError({
24
29
  name: "DiffmapParseError",
25
30
  message: "diffmap could not parse markdown",
@@ -12,9 +12,17 @@ export function extractTitle(source: string) {
12
12
  export function extractFences(source: string) {
13
13
  const fences: Fence[] = [];
14
14
  for (const match of source.matchAll(fencePattern)) {
15
- const lang = match[1] ?? "";
15
+ const lang = (match[1] ?? "").trim();
16
16
  const body = match[2] ?? "";
17
- fences.push(parseFence(lang.trim(), body));
17
+ // A diagram's info string can add `diff`, and Mermaid a [Title].
18
+ const diagram = /^(mermaid|services)\b\s*(diff)?\s*(?:\[([^\]]*)\])?$/.exec(
19
+ lang,
20
+ );
21
+ fences.push(
22
+ diagram === null
23
+ ? parseFence(lang, body)
24
+ : parseFence(diagram[1]!, body, [], diagram[3], diagram[2]),
25
+ );
18
26
  }
19
27
  return fences;
20
28
  }
package/src/git.test.ts CHANGED
@@ -249,7 +249,7 @@ test("readDocumentChanges rejects unchanged files and ranges past the end", asyn
249
249
  const sha = (await git("rev-parse", "HEAD")).slice(0, 7);
250
250
  const check = (reference: { path: string; start?: number; end?: number }) =>
251
251
  readDocumentChanges(root, {
252
- changeRevs: [],
252
+ changeCards: [],
253
253
  references: [{ kind: "file", rev: sha, ...reference }],
254
254
  });
255
255
 
@@ -269,6 +269,18 @@ test("readDocumentChanges rejects unchanged files and ranges past the end", asyn
269
269
  unchanged instanceof Error ? unchanged.message : "",
270
270
  /gone\.ts is not changed/,
271
271
  );
272
+
273
+ const review = (paths: string[]) =>
274
+ readDocumentChanges(root, {
275
+ changeCards: [{ rev: sha, review: paths }],
276
+ references: [],
277
+ });
278
+ assert.equal((await review(["keep.ts"])) instanceof Error, false);
279
+ const missing = await review(["keep.ts", "gone.ts"]);
280
+ assert.match(
281
+ missing instanceof Error ? missing.message : "",
282
+ /lists gone\.ts to review, but it is not changed/,
283
+ );
272
284
  });
273
285
  });
274
286
 
package/src/git.ts CHANGED
@@ -462,10 +462,13 @@ function totals(entries: NumstatEntry[]) {
462
462
  */
463
463
  export async function readDocumentChanges(
464
464
  root: string,
465
- document: Pick<ViewerDocument, "references" | "changeRevs">,
465
+ document: Pick<ViewerDocument, "references" | "changeCards">,
466
466
  ): Promise<Map<Rev, Changes> | DiffmapGitError> {
467
467
  // Uncommitted revs are read live; only commits are checked and snapshotted.
468
- const revs = new Set<Rev>(document.changeRevs.filter(isCommitRev));
468
+ const commitCards = document.changeCards.filter((card) =>
469
+ isCommitRev(card.rev),
470
+ );
471
+ const revs = new Set<Rev>(commitCards.map((card) => card.rev));
469
472
  for (const reference of document.references) {
470
473
  if (reference.kind === "changes" || reference.rev !== undefined)
471
474
  revs.add(reference.rev!);
@@ -476,6 +479,16 @@ export async function readDocumentChanges(
476
479
  if (changes instanceof Error) return changes;
477
480
  loaded.set(rev, changes);
478
481
  }
482
+ for (const card of commitCards) {
483
+ const files = loaded.get(card.rev)!.files;
484
+ const missing = card.review.find(
485
+ (reviewPath) => !files.some((file) => file.path === reviewPath),
486
+ );
487
+ if (missing !== undefined)
488
+ return new DiffmapGitError({
489
+ reason: `changes ${card.rev} lists ${missing} to review, but it is not changed in ${card.rev}.`,
490
+ });
491
+ }
479
492
  for (const reference of document.references) {
480
493
  if (reference.kind !== "file" || reference.rev === undefined) continue;
481
494
  const file = loaded
@@ -12,10 +12,18 @@ import {
12
12
  } from "../viewer/changesSource.ts";
13
13
  import { HostFilesContext } from "./files.ts";
14
14
  import homeSource from "./home.md?raw";
15
- import cliSource from "../cli.ts?raw";
16
15
  import shareSource from "../share.ts?raw";
17
- import parseViewerSource from "../parseViewer.ts?raw";
18
- import githubRouteSource from "../github/route.ts?raw";
16
+ import serveSource from "../serve.ts?raw";
17
+ import gitSource from "../git.ts?raw";
18
+ import fetchRepoSource from "../github/fetchRepo.ts?raw";
19
+ import fenceSource from "../viewer/Fence.tsx?raw";
20
+ import callStackSource from "../viewer/CallStackDiff.tsx?raw";
21
+ import sourceNavigationSource from "../viewer/sourceNavigation.ts?raw";
22
+ import sourceDiffPanelSource from "../viewer/SourceDiffPanel.tsx?raw";
23
+ import viewerAppSource from "../viewer/ViewerApp.tsx?raw";
24
+ import parseFenceSource from "../parseFence.ts?raw";
25
+ import annotationsSource from "../annotations.ts?raw";
26
+ import hostFilesSource from "./files.ts?raw";
19
27
 
20
28
  let parserReady: Promise<void> | undefined;
21
29
 
@@ -25,10 +33,18 @@ function readyHostParser() {
25
33
  }
26
34
 
27
35
  const hostFiles = {
28
- "src/cli.ts": cliSource,
29
36
  "src/share.ts": shareSource,
30
- "src/parseViewer.ts": parseViewerSource,
31
- "src/github/route.ts": githubRouteSource,
37
+ "src/serve.ts": serveSource,
38
+ "src/git.ts": gitSource,
39
+ "src/github/fetchRepo.ts": fetchRepoSource,
40
+ "src/viewer/Fence.tsx": fenceSource,
41
+ "src/viewer/CallStackDiff.tsx": callStackSource,
42
+ "src/viewer/sourceNavigation.ts": sourceNavigationSource,
43
+ "src/viewer/SourceDiffPanel.tsx": sourceDiffPanelSource,
44
+ "src/viewer/ViewerApp.tsx": viewerAppSource,
45
+ "src/parseFence.ts": parseFenceSource,
46
+ "src/annotations.ts": annotationsSource,
47
+ "src/host/files.ts": hostFilesSource,
32
48
  };
33
49
 
34
50
  /** The homepage walks through diffmap's own commits, read from GitHub. */