@ttsc/graph 0.26.2 → 0.28.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.
Files changed (85) hide show
  1. package/README.md +3 -1
  2. package/lib/index.d.ts +1 -1
  3. package/lib/index.js +15 -3
  4. package/lib/index.js.map +1 -1
  5. package/lib/model/TtscGraphMemory.d.ts +26 -0
  6. package/lib/model/TtscGraphMemory.js +121 -2
  7. package/lib/model/TtscGraphMemory.js.map +1 -1
  8. package/lib/model/TtscGraphSession.d.ts +23 -0
  9. package/lib/model/TtscGraphSession.js +248 -96
  10. package/lib/model/TtscGraphSession.js.map +1 -1
  11. package/lib/model/TtscGraphShardStore.js +6 -1
  12. package/lib/model/TtscGraphShardStore.js.map +1 -1
  13. package/lib/model/TtscLintDaemon.d.ts +54 -0
  14. package/lib/model/TtscLintDaemon.js +166 -0
  15. package/lib/model/TtscLintDaemon.js.map +1 -0
  16. package/lib/model/loadGraph.d.ts +8 -1
  17. package/lib/model/loadGraph.js +144 -72
  18. package/lib/model/loadGraph.js.map +1 -1
  19. package/lib/model/publishedArtifacts.d.ts +142 -0
  20. package/lib/model/publishedArtifacts.js +403 -0
  21. package/lib/model/publishedArtifacts.js.map +1 -0
  22. package/lib/nativeExecutable.js +17 -1
  23. package/lib/nativeExecutable.js.map +1 -1
  24. package/lib/reduce.js +20 -7
  25. package/lib/reduce.js.map +1 -1
  26. package/lib/server/createServer.js +38 -2
  27. package/lib/server/createServer.js.map +1 -1
  28. package/lib/server/runDetails.d.ts +15 -0
  29. package/lib/server/runDetails.js +48 -0
  30. package/lib/server/runDetails.js.map +1 -1
  31. package/lib/server/runEntrypoints.js +7 -1
  32. package/lib/server/runEntrypoints.js.map +1 -1
  33. package/lib/server/runLookup.js +129 -11
  34. package/lib/server/runLookup.js.map +1 -1
  35. package/lib/structures/ITtscGraphApplication.d.ts +3 -1
  36. package/lib/structures/ITtscGraphDetails.d.ts +12 -0
  37. package/lib/structures/ITtscGraphDocTag.d.ts +44 -0
  38. package/lib/structures/ITtscGraphDocTag.js +3 -0
  39. package/lib/structures/ITtscGraphDocTag.js.map +1 -0
  40. package/lib/structures/ITtscGraphDump.d.ts +23 -4
  41. package/lib/structures/ITtscGraphLookup.d.ts +29 -0
  42. package/lib/structures/ITtscGraphNode.d.ts +25 -0
  43. package/lib/structures/TtscGraphArtifactNodeKind.d.ts +23 -0
  44. package/lib/structures/TtscGraphArtifactNodeKind.js +37 -0
  45. package/lib/structures/TtscGraphArtifactNodeKind.js.map +1 -0
  46. package/lib/structures/TtscGraphDumpEdgeKind.d.ts +1 -1
  47. package/lib/structures/TtscGraphDumpNodeKind.d.ts +10 -2
  48. package/lib/structures/TtscGraphEdgeKind.d.ts +8 -1
  49. package/lib/structures/TtscGraphNodeKind.d.ts +1 -1
  50. package/lib/structures/index.d.ts +2 -0
  51. package/lib/structures/index.js +2 -0
  52. package/lib/structures/index.js.map +1 -1
  53. package/lib/view.js +17 -1
  54. package/lib/view.js.map +1 -1
  55. package/lib/viewer/index.html +5 -13
  56. package/lib/viewer/viewer.js +190 -190
  57. package/package.json +5 -5
  58. package/src/index.ts +23 -6
  59. package/src/model/TtscGraphMemory.ts +118 -2
  60. package/src/model/TtscGraphSession.ts +112 -2
  61. package/src/model/TtscGraphShardStore.ts +6 -1
  62. package/src/model/TtscLintDaemon.ts +179 -0
  63. package/src/model/loadGraph.ts +29 -5
  64. package/src/model/publishedArtifacts.ts +548 -0
  65. package/src/nativeExecutable.ts +24 -1
  66. package/src/reduce.ts +20 -7
  67. package/src/server/runDetails.ts +52 -1
  68. package/src/server/runEntrypoints.ts +7 -1
  69. package/src/server/runLookup.ts +139 -14
  70. package/src/structures/ITtscGraphApplication.ts +3 -1
  71. package/src/structures/ITtscGraphDetails.ts +13 -0
  72. package/src/structures/ITtscGraphDocTag.ts +45 -0
  73. package/src/structures/ITtscGraphDump.ts +25 -4
  74. package/src/structures/ITtscGraphLookup.ts +31 -0
  75. package/src/structures/ITtscGraphNode.ts +27 -0
  76. package/src/structures/TtscGraphArtifactNodeKind.ts +35 -0
  77. package/src/structures/TtscGraphDumpEdgeKind.ts +1 -0
  78. package/src/structures/TtscGraphDumpNodeKind.ts +16 -2
  79. package/src/structures/TtscGraphEdgeKind.ts +8 -0
  80. package/src/structures/TtscGraphNodeKind.ts +7 -1
  81. package/src/structures/index.ts +2 -0
  82. package/src/view.ts +17 -1
  83. package/src/viewer/index.html +5 -13
  84. package/src/viewer/legend.ts +107 -0
  85. package/src/viewer/main.ts +19 -21
package/src/view.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  projectOptions,
11
11
  } from "./launcherArgs";
12
12
  import { parseDump } from "./model/loadGraph";
13
+ import { publishArtifacts } from "./model/publishedArtifacts";
13
14
  import { captureProcessOutput, ensureExecutable } from "./nativeExecutable";
14
15
  import { reduce } from "./reduce";
15
16
  import { resolveGraphBinary } from "./resolveGraphBinary";
@@ -76,9 +77,24 @@ export function runView(argv: readonly string[]): number | void {
76
77
  let dumpStdout: string;
77
78
  let dumpStderr: string;
78
79
  try {
80
+ // The same artifacts the dump, the loader, and the resident session ask
81
+ // for. Without this the viewer draws a different graph from the one every
82
+ // other entry point answers with — and it already carries the colours for
83
+ // the nodes it would be missing.
84
+ const artifacts = publishArtifacts({
85
+ cwd: opts.cwd,
86
+ tsconfig: opts.tsconfig,
87
+ });
79
88
  dump = spawnSync(
80
89
  binary,
81
- ["dump", "--cwd", opts.cwd, "--tsconfig", opts.tsconfig],
90
+ [
91
+ "dump",
92
+ "--cwd",
93
+ opts.cwd,
94
+ "--tsconfig",
95
+ opts.tsconfig,
96
+ ...(artifacts.file === null ? [] : ["--artifacts", artifacts.file]),
97
+ ],
82
98
  {
83
99
  stdio: ["ignore", capture.stdoutFd, capture.stderrFd],
84
100
  windowsHide: true,
@@ -102,19 +102,11 @@
102
102
  <span id="counts"></span>
103
103
  </header>
104
104
  <div id="graph"></div>
105
- <footer>
106
- <span class="dot"
107
- ><span class="swatch" style="background: #3fb950"></span
108
- >value-call</span
109
- >
110
- <span class="dot"
111
- ><span class="swatch" style="background: #f5b042"></span
112
- >type-ref</span
113
- >
114
- <span class="dot"
115
- ><span class="swatch" style="background: #6ea8ff"></span
116
- >heritage</span
117
- >
105
+ <!-- The edge-family swatches are prepended here from the one colour map
106
+ in legend.ts. They used to be written out by hand, so a new family
107
+ rendered in the graph with no entry beside it until someone opened
108
+ both files. -->
109
+ <footer id="legend">
118
110
  <span>node size = connection count · color = declaration kind</span>
119
111
  </footer>
120
112
  </div>
@@ -0,0 +1,107 @@
1
+ // The bundled viewer's display vocabulary and the legend it renders from it.
2
+ //
3
+ // Separate from `main.ts` because that module fetches and renders on import, so
4
+ // nothing can read its constants or exercise its legend without a browser. The
5
+ // legend is the surface this file exists to protect: it used to be literal
6
+ // markup in `index.html` with each colour repeated in a `style` attribute, and a
7
+ // new family shipped into the graph with no entry beside it until someone opened
8
+ // both files.
9
+
10
+ /** The slice of the DOM the legend needs, so a test can drive it without one. */
11
+ export interface LegendElement {
12
+ className: string;
13
+ style: { background: string };
14
+ // `unknown[]`, because the real `Document` types these as `(Node | string)[]`
15
+ // and a narrower parameter is not assignable to it. `src/viewer` is excluded
16
+ // from the declaration build, so nothing would have reported that.
17
+ append(...nodes: unknown[]): void;
18
+ prepend(...nodes: unknown[]): void;
19
+ }
20
+
21
+ /** The slice of `document` the legend needs. */
22
+ export interface LegendDocument {
23
+ getElementById(id: string): LegendElement | null;
24
+ createElement(tag: string): LegendElement;
25
+ }
26
+
27
+ /**
28
+ * Node colour per declaration kind.
29
+ *
30
+ * Total over the kinds a dump can carry (`TtscGraphDumpNodeKind`). `module` was
31
+ * missing, and because the fallback below was the same string as `variable`, a
32
+ * module was not merely unnamed — it was drawn as a variable.
33
+ */
34
+ export const NODE_COLORS: Record<string, string> = {
35
+ // The artifacts. They are one hue family on purpose: a reader tells a document
36
+ // from a declaration at a glance, and tells the artifacts apart within it.
37
+ markdown_document: "#e8b4b8",
38
+ markdown_section: "#d99ba0",
39
+ prisma_model: "#b8a3e8",
40
+ prisma_column: "#a08fd0",
41
+ prisma_relation: "#8a76c0",
42
+ swagger_operation: "#e8d9a0",
43
+ module: "#d0d7de",
44
+ class: "#36e2ee",
45
+ interface: "#6ea8ff",
46
+ function: "#3fb950",
47
+ method: "#2bb673",
48
+ type: "#f5b042",
49
+ enum: "#c792ea",
50
+ variable: "#8b97a8",
51
+ };
52
+
53
+ /**
54
+ * Edge colour per display family.
55
+ *
56
+ * One definition: the edge colour, the legend swatch, and the legend name all
57
+ * read this map. `exports` is neutral because it is a structural relation
58
+ * rather than a use, and it is opaque so it stays apart from the translucent
59
+ * fallback.
60
+ */
61
+ export const LINK_COLORS: Record<string, string> = {
62
+ "value-call": "#3fb950",
63
+ "type-ref": "#f5b042",
64
+ "doc-ref": "#c07de0",
65
+ heritage: "#6ea8ff",
66
+ exports: "#7d8590",
67
+ };
68
+
69
+ /**
70
+ * What an unrecognized node kind is drawn in.
71
+ *
72
+ * It has to differ from every value in {@link NODE_COLORS}, or "I do not know
73
+ * this kind" and "this is a variable" are the same picture.
74
+ */
75
+ export const UNKNOWN_NODE_COLOR = "#565f6b";
76
+
77
+ /** What an unrecognized edge kind is drawn in; translucent, unlike a family. */
78
+ export const UNKNOWN_LINK_COLOR = "#ffffff55";
79
+
80
+ /** Elements whose legend is already built, so a second call adds nothing. */
81
+ const rendered = new WeakSet<LegendElement>();
82
+
83
+ /**
84
+ * Fill the footer legend from {@link LINK_COLORS}, so a family cannot be drawn
85
+ * without being named.
86
+ *
87
+ * The swatches are prepended, which puts them ahead of the static note the
88
+ * markup keeps — the order the hand-written markup had. The website viewer has
89
+ * always derived its legend this way
90
+ * (`website/src/components/graph/TtscWebsiteGraphViewer3D.tsx`).
91
+ */
92
+ export function renderLegend(host: LegendDocument): void {
93
+ const legend = host.getElementById("legend");
94
+ if (legend === null || rendered.has(legend)) return;
95
+ rendered.add(legend);
96
+ legend.prepend(
97
+ ...Object.entries(LINK_COLORS).map(([kind, color]) => {
98
+ const dot = host.createElement("span");
99
+ dot.className = "dot";
100
+ const swatch = host.createElement("span");
101
+ swatch.className = "swatch";
102
+ swatch.style.background = color;
103
+ dot.append(swatch, kind);
104
+ return dot;
105
+ }),
106
+ );
107
+ }
@@ -1,11 +1,21 @@
1
1
  // Vanilla 3D code-graph viewer bundled into @ttsc/graph by esbuild and served by
2
- // `ttsc-graph view`. Mirrors website/src/components/graph/GraphViewer3D.tsx, but
3
- // standalone (no React): fetch the reduced graph the CLI serves, render it on
4
- // three.js + three-forcegraph, and let the user orbit it.
2
+ // `ttsc-graph view`. Mirrors website/src/components/graph/TtscWebsiteGraphViewer3D.tsx,
3
+ // but standalone (no React): fetch the reduced graph the CLI serves, render it on
4
+ // three.js + three-forcegraph, and let the user orbit it. The display vocabulary
5
+ // and the legend live in ./legend, which this module has no side effects to hide
6
+ // from a test.
5
7
  import * as THREE from "three";
6
8
  import ThreeForceGraph from "three-forcegraph";
7
9
  import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
8
10
 
11
+ import {
12
+ LINK_COLORS,
13
+ NODE_COLORS,
14
+ UNKNOWN_LINK_COLOR,
15
+ UNKNOWN_NODE_COLOR,
16
+ renderLegend,
17
+ } from "./legend";
18
+
9
19
  interface GNode {
10
20
  id: string;
11
21
  name: string;
@@ -27,22 +37,6 @@ interface Payload {
27
37
  links: GLink[];
28
38
  }
29
39
 
30
- const NODE_COLORS: Record<string, string> = {
31
- class: "#36e2ee",
32
- interface: "#6ea8ff",
33
- function: "#3fb950",
34
- method: "#2bb673",
35
- type: "#f5b042",
36
- enum: "#c792ea",
37
- variable: "#8b97a8",
38
- };
39
-
40
- const LINK_COLORS: Record<string, string> = {
41
- "value-call": "#3fb950",
42
- "type-ref": "#f5b042",
43
- heritage: "#6ea8ff",
44
- };
45
-
46
40
  function escapeHtml(value: string): string {
47
41
  return value
48
42
  .replace(/&/g, "&amp;")
@@ -56,6 +50,10 @@ function setText(id: string, text: string): void {
56
50
  }
57
51
 
58
52
  async function main(): Promise<void> {
53
+ // Before the fetch, so a graph that fails to load still shows the legend the
54
+ // static markup used to guarantee.
55
+ renderLegend(document);
56
+
59
57
  const container = document.getElementById("graph");
60
58
  if (!container) return;
61
59
 
@@ -103,8 +101,8 @@ async function main(): Promise<void> {
103
101
  .nodeResolution(12)
104
102
  .nodeOpacity(0.95)
105
103
  .nodeVal((node) => 1 + Math.sqrt(node.degree))
106
- .nodeColor((node) => NODE_COLORS[node.kind] ?? "#8b97a8")
107
- .linkColor((link) => LINK_COLORS[link.kind] ?? "#ffffff55")
104
+ .nodeColor((node) => NODE_COLORS[node.kind] ?? UNKNOWN_NODE_COLOR)
105
+ .linkColor((link) => LINK_COLORS[link.kind] ?? UNKNOWN_LINK_COLOR)
108
106
  .linkOpacity(0.4)
109
107
  .linkWidth(0)
110
108
  .warmupTicks(20)