@tanishqkancharla/diffmap 0.1.3 → 0.1.5

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 (50) hide show
  1. package/README.md +25 -14
  2. package/package.json +3 -3
  3. package/src/cli.test.ts +50 -0
  4. package/src/cli.ts +126 -51
  5. package/src/contentPlugin.ts +5 -3
  6. package/src/errors.ts +6 -1
  7. package/src/gist/GistApp.tsx +34 -21
  8. package/src/gist/GistStatus.tsx +8 -43
  9. package/src/gist/main.tsx +2 -2
  10. package/src/gist/pin.ts +14 -0
  11. package/src/github/GitHubApp.tsx +235 -0
  12. package/src/github/fetchRepo.test.ts +17 -0
  13. package/src/github/fetchRepo.ts +300 -0
  14. package/src/github/patch.test.ts +30 -0
  15. package/src/github/patch.ts +40 -0
  16. package/src/github/pin.ts +14 -0
  17. package/src/github/route.test.ts +68 -0
  18. package/src/github/route.ts +175 -0
  19. package/src/host/HostApp.tsx +22 -0
  20. package/src/host/HostHome.tsx +73 -0
  21. package/src/host/files.ts +10 -0
  22. package/src/host/home.md +194 -0
  23. package/src/host/home.test.ts +82 -0
  24. package/src/index.ts +1 -0
  25. package/src/mermaid.ts +29 -1
  26. package/src/packageVersion.ts +7 -0
  27. package/src/parseViewer.test.ts +185 -0
  28. package/src/parseViewer.ts +27 -3
  29. package/src/serve.test.ts +306 -0
  30. package/src/serve.ts +23 -5
  31. package/src/share.ts +5 -1
  32. package/src/update.test.ts +19 -0
  33. package/src/update.ts +285 -0
  34. package/src/viewer/CallStackDiff.tsx +26 -6
  35. package/src/viewer/CloseServerButton.tsx +16 -0
  36. package/src/viewer/FileExcerpt.tsx +52 -3
  37. package/src/viewer/HtmlPlaceholder.tsx +6 -1
  38. package/src/viewer/SourceDiffPanel.tsx +155 -59
  39. package/src/viewer/TableOfContents.tsx +230 -39
  40. package/src/viewer/TocButton.tsx +27 -0
  41. package/src/viewer/ViewerApp.tsx +182 -47
  42. package/src/viewer/main.tsx +10 -3
  43. package/src/viewer/sourceHeader.test.ts +131 -0
  44. package/src/viewer/sourceHeader.ts +103 -0
  45. package/src/viewer/sourceNavigation.ts +81 -3
  46. package/src/viewer/viewerMode.ts +1 -1
  47. package/src/viewer/vite-env.d.ts +2 -1
  48. package/vite.config.ts +1 -1
  49. package/src/viewer/Check.tsx +0 -24
  50. package/src/viewer/DoneButton.tsx +0 -32
@@ -1,8 +1,12 @@
1
- import { useEffect, useState } from "react";
1
+ import { useEffect, useMemo, useState } from "react";
2
2
  import type { CodeViewDiffItem, CodeViewLineSelection } from "@pierre/diffs";
3
3
  import type { SourceReference } from "../annotations.js";
4
4
  import type { SourceDefinition, DefinitionResponse } from "../definitions.js";
5
5
  import { DiffmapDefinitionError } from "../errors.js";
6
+ import { useGitHubPin } from "../github/pin.ts";
7
+ import { fetchPinnedBlob, findSymbolLineRange } from "../github/fetchRepo.ts";
8
+ import { useHostFiles } from "../host/files.ts";
9
+ import { useViewerMode } from "./viewerMode.ts";
6
10
 
7
11
  export async function requestSource(
8
12
  endpoint: "source" | "definition",
@@ -42,14 +46,61 @@ export function useSourceReference(reference: SourceReference | undefined) {
42
46
  reference: SourceReference;
43
47
  result: SourceDefinition | Error;
44
48
  }>();
49
+ const pin = useGitHubPin();
50
+ const hostFiles = useHostFiles();
51
+ const mode = useViewerMode();
52
+ const hostResult = useMemo(() => {
53
+ if (reference?.kind !== "file" || hostFiles === undefined) return undefined;
54
+ return readHostFileReference(hostFiles, reference);
55
+ }, [reference, hostFiles]);
45
56
  useEffect(() => {
46
57
  if (reference?.kind !== "file") return;
58
+ if (hostFiles !== undefined) return;
59
+ let active = true;
60
+ if (pin !== undefined) {
61
+ // Pinned GitHub spec: load this path at the spec commit SHA, never main.
62
+ // oxlint-disable-next-line typescript/no-floating-promises -- The effect owns its asynchronous source result.
63
+ void fetchPinnedBlob(pin, reference.path).then((contents) => {
64
+ if (!active) return;
65
+ if (contents instanceof Error) {
66
+ const message =
67
+ contents.message === "not-found"
68
+ ? `Could not read ${reference.path} at this commit.`
69
+ : contents.message;
70
+ setResolution({
71
+ reference,
72
+ result: new DiffmapDefinitionError({ reason: message }),
73
+ });
74
+ return;
75
+ }
76
+ const lineCount = Math.max(1, contents.split(/\r?\n/).length);
77
+ const range =
78
+ reference.symbol !== undefined
79
+ ? findSymbolLineRange(contents, reference.symbol)
80
+ : {
81
+ start: reference.start ?? 1,
82
+ end: reference.end ?? lineCount,
83
+ };
84
+ setResolution({
85
+ reference,
86
+ result: {
87
+ path: reference.path,
88
+ contents,
89
+ start: range.start,
90
+ end: range.end,
91
+ },
92
+ });
93
+ });
94
+ return () => {
95
+ active = false;
96
+ };
97
+ }
98
+ if (mode !== "local") return;
47
99
  const params = new URLSearchParams({ path: reference.path });
48
100
  if (reference.symbol !== undefined) params.set("symbol", reference.symbol);
49
101
  if (reference.start !== undefined)
50
102
  params.set("start", String(reference.start));
51
103
  if (reference.end !== undefined) params.set("end", String(reference.end));
52
- let active = true;
53
104
  // oxlint-disable-next-line typescript/no-floating-promises -- The effect owns its asynchronous source result.
54
105
  void requestSource("source", params).then((result) => {
55
106
  if (active) setResolution({ reference, result });
@@ -57,10 +108,37 @@ export function useSourceReference(reference: SourceReference | undefined) {
57
108
  return () => {
58
109
  active = false;
59
110
  };
60
- }, [reference]);
111
+ }, [reference, pin, mode, hostFiles]);
112
+ if (hostResult !== undefined) return hostResult;
61
113
  return resolution?.reference === reference ? resolution?.result : undefined;
62
114
  }
63
115
 
116
+ function readHostFileReference(
117
+ files: Record<string, string>,
118
+ reference: Extract<SourceReference, { kind: "file" }>,
119
+ ): SourceDefinition | Error {
120
+ const contents = files[reference.path];
121
+ if (contents === undefined) {
122
+ return new DiffmapDefinitionError({
123
+ reason: `No hosted file for ${reference.path}.`,
124
+ });
125
+ }
126
+ const lineCount = Math.max(1, contents.split(/\r?\n/).length);
127
+ const range =
128
+ reference.symbol !== undefined
129
+ ? findSymbolLineRange(contents, reference.symbol)
130
+ : {
131
+ start: reference.start ?? 1,
132
+ end: reference.end ?? lineCount,
133
+ };
134
+ return {
135
+ path: reference.path,
136
+ contents,
137
+ start: range.start,
138
+ end: range.end,
139
+ };
140
+ }
141
+
64
142
  export function matchingSourceDiff(
65
143
  source: SourceDefinition,
66
144
  items: CodeViewDiffItem[],
@@ -1,6 +1,6 @@
1
1
  import { createContext, useContext } from "react";
2
2
 
3
- export type ViewerMode = "local" | "gist";
3
+ export type ViewerMode = "local" | "gist" | "github" | "host";
4
4
 
5
5
  export const ViewerModeContext = createContext<ViewerMode>("local");
6
6
 
@@ -1,4 +1,5 @@
1
1
  declare module "virtual:diffmap" {
2
2
  import type { ViewerDocument } from "../parseViewer.js";
3
- export const viewerDocument: ViewerDocument;
3
+ export const viewerDocument: ViewerDocument | null;
4
+ export const parseError: string | null;
4
5
  }
package/vite.config.ts CHANGED
@@ -34,7 +34,7 @@ export default defineConfig(({ command }) => {
34
34
  },
35
35
  clearScreen: false,
36
36
  server: {
37
- port: 4177,
37
+ port: 0,
38
38
  strictPort: false,
39
39
  },
40
40
  };
@@ -1,24 +0,0 @@
1
- import type { SVGProps } from "react";
2
-
3
- export function Check(props: SVGProps<SVGSVGElement>) {
4
- return (
5
- <svg
6
- focusable="false"
7
- aria-hidden="true"
8
- role="img"
9
- width={24}
10
- height={24}
11
- fill="none"
12
- viewBox="0 0 24 24"
13
- {...props}
14
- >
15
- <path
16
- stroke="currentColor"
17
- strokeLinecap="round"
18
- strokeLinejoin="round"
19
- strokeWidth={1.5}
20
- d="M5.75 12.5L10 16.75L18.25 7.25"
21
- />
22
- </svg>
23
- );
24
- }
@@ -1,32 +0,0 @@
1
- import { Button, background, colors, iconSizeValues, text } from "maui";
2
- import { style, useStyles } from "purse-styles";
3
- import { Check } from "./Check.tsx";
4
-
5
- const checkIcon = style({
6
- width: iconSizeValues.sm,
7
- height: iconSizeValues.sm,
8
- });
9
-
10
- export function DoneButton(props: { onClick?: () => void }) {
11
- const checkClass = useStyles(checkIcon);
12
- const primaryClass = useStyles(primaryButtonClass);
13
- return (
14
- <Button className={primaryClass} onClick={props.onClick}>
15
- <Check className={checkClass} />
16
- Done
17
- </Button>
18
- );
19
- }
20
-
21
- const primaryButtonClass = style(
22
- background.accent,
23
- text({ size: "xs", fontWeight: 400, color: "onAccent" }),
24
- {
25
- "&:hover": {
26
- backgroundColor: colors.accent[10],
27
- },
28
- "&:active": {
29
- backgroundColor: colors.accent[11],
30
- },
31
- },
32
- );