@coldtea/pr-lens-renderer 0.1.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 (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +91 -0
  3. package/dist/bounds.d.ts +23 -0
  4. package/dist/bounds.d.ts.map +1 -0
  5. package/dist/bounds.js +39 -0
  6. package/dist/bounds.js.map +1 -0
  7. package/dist/corrections.d.ts +12 -0
  8. package/dist/corrections.d.ts.map +1 -0
  9. package/dist/corrections.js +122 -0
  10. package/dist/corrections.js.map +1 -0
  11. package/dist/design.d.ts +112 -0
  12. package/dist/design.d.ts.map +1 -0
  13. package/dist/design.js +112 -0
  14. package/dist/design.js.map +1 -0
  15. package/dist/errors.d.ts +11 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +9 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/geometry.d.ts +20 -0
  20. package/dist/geometry.d.ts.map +1 -0
  21. package/dist/geometry.js +15 -0
  22. package/dist/geometry.js.map +1 -0
  23. package/dist/glob.d.ts +7 -0
  24. package/dist/glob.d.ts.map +1 -0
  25. package/dist/glob.js +17 -0
  26. package/dist/glob.js.map +1 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +8 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/layout/architecture.d.ts +78 -0
  32. package/dist/layout/architecture.d.ts.map +1 -0
  33. package/dist/layout/architecture.js +207 -0
  34. package/dist/layout/architecture.js.map +1 -0
  35. package/dist/layout/congestion.d.ts +18 -0
  36. package/dist/layout/congestion.d.ts.map +1 -0
  37. package/dist/layout/congestion.js +50 -0
  38. package/dist/layout/congestion.js.map +1 -0
  39. package/dist/layout/dataflow.d.ts +85 -0
  40. package/dist/layout/dataflow.d.ts.map +1 -0
  41. package/dist/layout/dataflow.js +184 -0
  42. package/dist/layout/dataflow.js.map +1 -0
  43. package/dist/layout/edges.d.ts +48 -0
  44. package/dist/layout/edges.d.ts.map +1 -0
  45. package/dist/layout/edges.js +843 -0
  46. package/dist/layout/edges.js.map +1 -0
  47. package/dist/layout/labels.d.ts +9 -0
  48. package/dist/layout/labels.d.ts.map +1 -0
  49. package/dist/layout/labels.js +149 -0
  50. package/dist/layout/labels.js.map +1 -0
  51. package/dist/layout/rank.d.ts +16 -0
  52. package/dist/layout/rank.d.ts.map +1 -0
  53. package/dist/layout/rank.js +80 -0
  54. package/dist/layout/rank.js.map +1 -0
  55. package/dist/layout/seating.d.ts +29 -0
  56. package/dist/layout/seating.d.ts.map +1 -0
  57. package/dist/layout/seating.js +131 -0
  58. package/dist/layout/seating.js.map +1 -0
  59. package/dist/manifest.d.ts +39 -0
  60. package/dist/manifest.d.ts.map +1 -0
  61. package/dist/manifest.js +99 -0
  62. package/dist/manifest.js.map +1 -0
  63. package/dist/render.d.ts +49 -0
  64. package/dist/render.d.ts.map +1 -0
  65. package/dist/render.js +125 -0
  66. package/dist/render.js.map +1 -0
  67. package/dist/scope.d.ts +21 -0
  68. package/dist/scope.d.ts.map +1 -0
  69. package/dist/scope.js +57 -0
  70. package/dist/scope.js.map +1 -0
  71. package/dist/svg/architecture.d.ts +15 -0
  72. package/dist/svg/architecture.d.ts.map +1 -0
  73. package/dist/svg/architecture.js +197 -0
  74. package/dist/svg/architecture.js.map +1 -0
  75. package/dist/svg/dataflow.d.ts +9 -0
  76. package/dist/svg/dataflow.d.ts.map +1 -0
  77. package/dist/svg/dataflow.js +284 -0
  78. package/dist/svg/dataflow.js.map +1 -0
  79. package/dist/svg/document.d.ts +37 -0
  80. package/dist/svg/document.d.ts.map +1 -0
  81. package/dist/svg/document.js +148 -0
  82. package/dist/svg/document.js.map +1 -0
  83. package/dist/svg/icons.d.ts +3 -0
  84. package/dist/svg/icons.d.ts.map +1 -0
  85. package/dist/svg/icons.js +106 -0
  86. package/dist/svg/icons.js.map +1 -0
  87. package/dist/svg/primitives.d.ts +13 -0
  88. package/dist/svg/primitives.d.ts.map +1 -0
  89. package/dist/svg/primitives.js +34 -0
  90. package/dist/svg/primitives.js.map +1 -0
  91. package/dist/svg/pulse.d.ts +24 -0
  92. package/dist/svg/pulse.d.ts.map +1 -0
  93. package/dist/svg/pulse.js +33 -0
  94. package/dist/svg/pulse.js.map +1 -0
  95. package/dist/text.d.ts +18 -0
  96. package/dist/text.d.ts.map +1 -0
  97. package/dist/text.js +70 -0
  98. package/dist/text.js.map +1 -0
  99. package/dist/theme.d.ts +44 -0
  100. package/dist/theme.d.ts.map +1 -0
  101. package/dist/theme.js +72 -0
  102. package/dist/theme.js.map +1 -0
  103. package/dist/version.d.ts +9 -0
  104. package/dist/version.d.ts.map +1 -0
  105. package/dist/version.js +9 -0
  106. package/dist/version.js.map +1 -0
  107. package/package.json +56 -0
  108. package/src/bounds.ts +50 -0
  109. package/src/corrections.ts +166 -0
  110. package/src/design.ts +124 -0
  111. package/src/errors.ts +21 -0
  112. package/src/geometry.ts +22 -0
  113. package/src/glob.ts +20 -0
  114. package/src/index.ts +30 -0
  115. package/src/layout/architecture.ts +324 -0
  116. package/src/layout/congestion.ts +76 -0
  117. package/src/layout/dataflow.ts +307 -0
  118. package/src/layout/edges.ts +1061 -0
  119. package/src/layout/labels.ts +192 -0
  120. package/src/layout/rank.ts +95 -0
  121. package/src/layout/seating.ts +189 -0
  122. package/src/manifest.ts +118 -0
  123. package/src/render.ts +190 -0
  124. package/src/scope.ts +67 -0
  125. package/src/svg/architecture.ts +293 -0
  126. package/src/svg/dataflow.ts +408 -0
  127. package/src/svg/document.ts +198 -0
  128. package/src/svg/icons.ts +121 -0
  129. package/src/svg/primitives.ts +50 -0
  130. package/src/svg/pulse.ts +48 -0
  131. package/src/text.ts +92 -0
  132. package/src/theme.ts +107 -0
  133. package/src/version.ts +9 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ohans Emmanuel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # @coldtea/pr-lens-renderer
2
+
3
+ A schema-valid PR Lens graph document in, a self-contained animated SVG out. No network, no filesystem, no clock: the same document renders to the same bytes on any machine, which is what lets a diagram be addressed by the hash of itself.
4
+
5
+ MIT © Ohans Emmanuel.
6
+
7
+ ```bash
8
+ pnpm add @coldtea/pr-lens-renderer
9
+ ```
10
+
11
+ ```ts
12
+ import { parseGraphDoc } from "@coldtea/pr-lens-schema";
13
+ import { render, renderAll } from "@coldtea/pr-lens-renderer";
14
+
15
+ const doc = parseGraphDoc(json);
16
+
17
+ // One diagram.
18
+ const { svg, width, height } = render(doc, { lens: "architecture", theme: "dark" });
19
+
20
+ // Every drill-down section, in both themes, plus the manifest a comment is built from.
21
+ const { assets, manifest } = renderAll(doc, { config });
22
+ ```
23
+
24
+ ## Two lenses
25
+
26
+ `architecture` draws lanes of cards with the change written into them: a coloured outline and a badge per delta, removed elements ghosted and struck through, edges tinted by their own delta, one hero edge with a glow, and a travelling pulse on anything the document marked `animated`.
27
+
28
+ `data-flow` draws a flow as a sequence: participant columns, lifelines, activation bars, return arrows, self-messages, and the architecture lens's travelling pulse on every step the document marks `animated`. Those steps share one cycle and take it in turn — one dot crossing one arrow at a time, in the order the steps happen, a repeated step taking consecutive turns. A turn is spent entirely on its crossing, so the next arrow lights as the last dot lands.
29
+
30
+ ## Rendering for a GitHub comment
31
+
32
+ Every file is self-contained. No script, no external stylesheet, no image, no font file, and no CSS custom property that would need the surrounding page — GitHub serves comment images through a proxy where that page does not exist. Animation is SMIL, which survives being loaded as an `<img>`; the exact patterns here are the ones proven to play inside a real pull request comment.
33
+
34
+ Themes are separate files rather than one file that adapts, because an image cannot see the theme of the page it lands in. Render both and pair them:
35
+
36
+ ```html
37
+ <picture>
38
+ <source media="(prefers-color-scheme: dark)" srcset="…-dark.svg">
39
+ <img src="…-light.svg" alt="…">
40
+ </picture>
41
+ ```
42
+
43
+ ## Determinism
44
+
45
+ The hard requirement is that a diagram does not rearrange itself between two pushes that barely changed anything.
46
+
47
+ - **Depth** is a longest path from a source, so an arrow points at a node below the one it left. Cycles are ranked too, by dropping the edge that closes one — chosen by a walk in document order, not by map iteration order.
48
+ - **`layout.rank` and `layout.laneOrder` are hints**, applied as a floor rather than an answer. A hint can push a node further down; it cannot lift one above what feeds it. A stale hint from an extraction model therefore cannot invert an edge.
49
+ - **Depth is counted within a lane.** A lane that only enters the story late still starts at the top of its column, and a rank no card in the lane occupies leaves no empty row behind.
50
+ - **Text is measured from a table**, never from a font engine, so a CI runner with no fonts installed lays out identically to a laptop with all of them.
51
+ - **Every coordinate is rounded before it is written**, and every comparison is by code unit rather than by `localeCompare`. Arithmetic that differs in the last bit — or a sort that consults the host's collation data — would change the bytes, and the render hash with it.
52
+ - **Every lane is the same fixed width**, a constant rather than anything derived from what the lanes hold. A width drawn from content couples every column to the contents of the ones before it, so adding one node with a long name to the first lane would slide every card in every later lane sideways. The cost is that a lane holding something narrow is wider than it needs to be; stability is worth more. A lane header too long for its band gives up its tail rather than widening the band.
53
+
54
+ Adding a node to one lane leaves every card in every other lane exactly where it was — before it or after it. There are tests for that, and golden SVGs for the reference documents: a change to one is a change to what a reviewer sees, so it is reviewed by a person before it is committed.
55
+
56
+ ```bash
57
+ pnpm test # compares against the goldens
58
+ UPDATE_GOLDENS=1 pnpm test # records them, for a human to read the diff of
59
+ ```
60
+
61
+ ## Corrections
62
+
63
+ A repository's `.github/pr-lens.yml` is an overlay, applied here before layout and never written back into inference, so a correction keeps holding as the code moves:
64
+
65
+ ```ts
66
+ render(doc, { lens: "architecture", theme: "dark", config });
67
+ ```
68
+
69
+ `rename`, `lane` and `group` address nodes by `id:<node-id>` or by a glob over the paths backing them. A `lane` correction may name a band the document never declared; it gets created, with the id for a label, so write `lane: infrastructure` rather than `lane: l3`.
70
+
71
+ `exclude` takes with it every edge and flow step that touched what it removed, every view that pointed at nothing else, and every layout hint left naming something that is gone — half an arrow is worse than none, and the corrected document is a document like any other, so it still parses.
72
+
73
+ ## Addresses
74
+
75
+ Renders are content-addressed because GitHub's image proxy caches hard: a changed diagram has to arrive as a new URL, not as new bytes at the old one. `contentHash`, `renderAssetId` and `renderAssetFileName` are the single owners of that format, and every surface that builds such a URL must go through them.
76
+
77
+ An asset's `path` is safe to join to an output directory, and its `id` is always a legal `Id`. View ids are authored by an extraction model and the contract lets one contain `/`, `:` and `.`, so `a/../../elsewhere` is a valid id; those characters are re-spelled one-for-one on the way into an address, which cannot produce a separator or a dot segment. Re-spelling can lengthen an id that was already near the contract's limit, so one that would overflow keeps a readable prefix and ends in a digest of the whole original — which is what stops two different views being handed the same address.
78
+
79
+ ## Untrusted text
80
+
81
+ Labels, subtitles and titles come from a model. They are escaped for XML at the boundary, and the code points XML 1.0 has no spelling for — most control characters, lone surrogates, the two non-characters — are dropped there too, because the schema constrains how long a label is but not which characters it may contain, and one of those would make the file fail to parse rather than merely look wrong.
82
+
83
+ ## Refusals
84
+
85
+ `PrLensRenderError` carries a `code` a caller can switch on: `UNKNOWN_VIEW`, `LENS_NOT_DECLARED`, `NOTHING_TO_RENDER`, `NO_FLOW_IN_SCOPE`, `TOO_MANY_ASSETS`. A document that parsed is otherwise safe to render — the renderer trusts `@coldtea/pr-lens-schema` and never re-validates it.
86
+
87
+ `TOO_MANY_ASSETS` cannot be reached by a parsed document: the contract caps a view tree at `MAX_VIEWS`, which is `MAX_RENDER_ASSETS` divided by the two themes a `<picture>` pair needs. A hand-built one can reach it, because that cap lives in a refinement and a refinement does not survive into the inferred type. The check is a postcondition on what `renderAll` is about to produce rather than a re-reading of what came in — how many pictures a render makes depends on how many themes the caller asked for, which no document knows.
88
+
89
+ ---
90
+
91
+ Part of [PR Lens](https://prlens.dev) — review what actually matters.
@@ -0,0 +1,23 @@
1
+ import type { Box } from "./geometry.js";
2
+ /** The smallest box containing all of them, or nothing when there are none. */
3
+ export declare const union: (boxes: readonly Box[]) => Box | undefined;
4
+ export type Canvas = {
5
+ width: number;
6
+ height: number;
7
+ shiftX: number;
8
+ shiftY: number;
9
+ };
10
+ /**
11
+ * A canvas big enough for everything that was drawn.
12
+ *
13
+ * Edge routes deliberately leave their lane, and a label pill can be pushed
14
+ * past the last card in search of clear air, so the space the lanes occupy is
15
+ * a floor rather than the answer. The canvas only ever grows: the margins the
16
+ * design leaves above and beside the lanes are part of the design, not slack
17
+ * to be reclaimed.
18
+ */
19
+ export declare const canvasFor: (laid: {
20
+ width: number;
21
+ height: number;
22
+ }, drawn: Box | undefined, margin: number) => Canvas;
23
+ //# sourceMappingURL=bounds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bounds.d.ts","sourceRoot":"","sources":["../src/bounds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEzC,+EAA+E;AAC/E,eAAO,MAAM,KAAK,UAAW,SAAS,GAAG,EAAE,KAAG,GAAG,GAAG,SAiBnD,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,SACd;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,SAChC,GAAG,GAAG,SAAS,UACd,MAAM,KACb,MAYF,CAAC"}
package/dist/bounds.js ADDED
@@ -0,0 +1,39 @@
1
+ /** The smallest box containing all of them, or nothing when there are none. */
2
+ export const union = (boxes) => {
3
+ const first = boxes[0];
4
+ if (first === undefined)
5
+ return undefined;
6
+ let left = first.x;
7
+ let top = first.y;
8
+ let right = first.x + first.width;
9
+ let bottom = first.y + first.height;
10
+ for (const box of boxes) {
11
+ left = Math.min(left, box.x);
12
+ top = Math.min(top, box.y);
13
+ right = Math.max(right, box.x + box.width);
14
+ bottom = Math.max(bottom, box.y + box.height);
15
+ }
16
+ return { x: left, y: top, width: right - left, height: bottom - top };
17
+ };
18
+ /**
19
+ * A canvas big enough for everything that was drawn.
20
+ *
21
+ * Edge routes deliberately leave their lane, and a label pill can be pushed
22
+ * past the last card in search of clear air, so the space the lanes occupy is
23
+ * a floor rather than the answer. The canvas only ever grows: the margins the
24
+ * design leaves above and beside the lanes are part of the design, not slack
25
+ * to be reclaimed.
26
+ */
27
+ export const canvasFor = (laid, drawn, margin) => {
28
+ if (drawn === undefined)
29
+ return { width: laid.width, height: laid.height, shiftX: 0, shiftY: 0 };
30
+ const shiftX = Math.max(0, margin - drawn.x);
31
+ const shiftY = Math.max(0, margin - drawn.y);
32
+ return {
33
+ width: Math.ceil(Math.max(laid.width, drawn.x + drawn.width + margin) + shiftX),
34
+ height: Math.ceil(Math.max(laid.height, drawn.y + drawn.height + margin) + shiftY),
35
+ shiftX,
36
+ shiftY,
37
+ };
38
+ };
39
+ //# sourceMappingURL=bounds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bounds.js","sourceRoot":"","sources":["../src/bounds.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAqB,EAAmB,EAAE;IAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE1C,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC;IACnB,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC;IAClB,IAAI,KAAK,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;IAClC,IAAI,MAAM,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IAEpC,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7B,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3B,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,EAAE,CAAC;AACxE,CAAC,CAAC;AAIF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAuC,EACvC,KAAsB,EACtB,MAAc,EACN,EAAE;IACV,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAEjG,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAE7C,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC;QAC/E,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC;QAClF,MAAM;QACN,MAAM;KACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { GraphDoc, MapCorrections } from "@coldtea/pr-lens-schema";
2
+ /**
3
+ * Applies a repository's corrections over an inferred document.
4
+ *
5
+ * The overlay is re-applied to fresh inference on every run, so a correction
6
+ * keeps holding as the code moves and inference never learns to agree with
7
+ * it. Everything a removed node touched goes with it: an edge to a node that
8
+ * is no longer drawn would point at empty space, and a flow step from one
9
+ * would animate out of nowhere.
10
+ */
11
+ export declare const applyCorrections: (doc: GraphDoc, corrections: MapCorrections) => GraphDoc;
12
+ //# sourceMappingURL=corrections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corrections.d.ts","sourceRoot":"","sources":["../src/corrections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,QAAQ,EAIR,cAAc,EAGf,MAAM,yBAAyB,CAAC;AAmDjC;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,QAAS,QAAQ,eAAe,cAAc,KAAG,QAsE7E,CAAC"}
@@ -0,0 +1,122 @@
1
+ import { assertNever } from "@coldtea/pr-lens-schema";
2
+ import { PrLensRenderError } from "./errors.js";
3
+ import { matchesGlob } from "./glob.js";
4
+ const ID_SELECTOR = "id:";
5
+ const selects = (selector, node) => {
6
+ if (selector.startsWith(ID_SELECTOR))
7
+ return node.id === selector.slice(ID_SELECTOR.length);
8
+ return node.files.some((file) => matchesGlob(selector, file.path));
9
+ };
10
+ /**
11
+ * A view of a selection with the ids the overlay removed taken out, or
12
+ * `undefined` when nothing it pointed at survived. A selection is never
13
+ * allowed to empty out into "show everything": that is a different view.
14
+ */
15
+ const narrowScope = (scope, survives) => {
16
+ switch (scope.kind) {
17
+ case "all":
18
+ return scope;
19
+ case "selection": {
20
+ const narrowed = {
21
+ kind: "selection",
22
+ lanes: scope.lanes.filter(survives.lane),
23
+ nodes: scope.nodes.filter(survives.node),
24
+ edges: scope.edges.filter(survives.edge),
25
+ flows: scope.flows.filter(survives.flow),
26
+ };
27
+ const total = narrowed.lanes.length + narrowed.nodes.length + narrowed.edges.length + narrowed.flows.length;
28
+ return total > 0 ? narrowed : undefined;
29
+ }
30
+ default:
31
+ return assertNever(scope, "Unhandled view scope");
32
+ }
33
+ };
34
+ const narrowViews = (views, survives) => views.flatMap((view) => {
35
+ const scope = narrowScope(view.scope, survives);
36
+ if (scope === undefined)
37
+ return [];
38
+ return [{ ...view, scope, children: narrowViews(view.children, survives) }];
39
+ });
40
+ /**
41
+ * Applies a repository's corrections over an inferred document.
42
+ *
43
+ * The overlay is re-applied to fresh inference on every run, so a correction
44
+ * keeps holding as the code moves and inference never learns to agree with
45
+ * it. Everything a removed node touched goes with it: an edge to a node that
46
+ * is no longer drawn would point at empty space, and a flow step from one
47
+ * would animate out of nowhere.
48
+ */
49
+ export const applyCorrections = (doc, corrections) => {
50
+ const excluded = new Set(doc.nodes.filter((node) => corrections.exclude.some((selector) => selects(selector, node))).map((node) => node.id));
51
+ const nodes = doc.nodes
52
+ .filter((node) => !excluded.has(node.id))
53
+ .map((node) => {
54
+ const rename = corrections.rename.find((rule) => selects(rule.match, node));
55
+ const lane = corrections.lane.find((rule) => selects(rule.match, node));
56
+ const group = corrections.group.find((rule) => selects(rule.match, node));
57
+ return {
58
+ ...node,
59
+ label: rename ? rename.to : node.label,
60
+ lane: lane ? lane.lane : node.lane,
61
+ group: group ? group.group : node.group,
62
+ };
63
+ });
64
+ if (nodes.length === 0)
65
+ throw new PrLensRenderError("NOTHING_TO_RENDER", "the exclude rules in this repository's config removed every node");
66
+ /**
67
+ * A `lane` correction may name a band the document never declared, which is
68
+ * how a repository adds one of its own. It gets the id for a label, since
69
+ * that is the only name the config carries.
70
+ */
71
+ const declared = new Set(doc.lanes.map((lane) => lane.id));
72
+ const invented = [...new Set(nodes.map((node) => node.lane))]
73
+ .filter((id) => !declared.has(id))
74
+ .map((id) => ({ id, label: id }));
75
+ const lanes = [...doc.lanes, ...invented];
76
+ const edges = doc.edges.filter((edge) => !excluded.has(edge.from) && !excluded.has(edge.to));
77
+ const flows = doc.flows.flatMap((flow) => {
78
+ const participants = flow.participants.filter((participant) => !excluded.has(participant.node));
79
+ if (participants.length < 2)
80
+ return [];
81
+ const kept = new Set(participants.map((participant) => participant.node));
82
+ const messages = flow.messages.filter((message) => kept.has(message.from) && kept.has(message.to));
83
+ if (messages.length === 0)
84
+ return [];
85
+ return [{ ...flow, participants, messages }];
86
+ });
87
+ const survives = {
88
+ lane: (id) => lanes.some((lane) => lane.id === id),
89
+ node: (id) => !excluded.has(id),
90
+ edge: (id) => edges.some((edge) => edge.id === id),
91
+ flow: (id) => flows.some((flow) => flow.id === id),
92
+ };
93
+ return {
94
+ ...doc,
95
+ lanes,
96
+ nodes,
97
+ edges,
98
+ flows,
99
+ views: narrowViews(doc.views, survives),
100
+ layout: narrowLayout(doc.layout, survives),
101
+ };
102
+ };
103
+ /**
104
+ * Layout hints name nodes and lanes, so an exclusion can leave one pointing at
105
+ * something that is no longer there. The renderer would not notice — a hint
106
+ * for a node it is not drawing simply goes unread — but the corrected document
107
+ * is a document like any other, and a surface that writes it out and parses it
108
+ * back is entitled to have it still be valid.
109
+ */
110
+ const narrowLayout = (layout, survives) => {
111
+ if (layout === undefined)
112
+ return undefined;
113
+ const rank = layout.rank === undefined
114
+ ? undefined
115
+ : Object.fromEntries(Object.entries(layout.rank).filter(([id]) => survives.node(id)));
116
+ return {
117
+ ...layout,
118
+ laneOrder: layout.laneOrder.filter(survives.lane),
119
+ ...(rank === undefined ? {} : { rank }),
120
+ };
121
+ };
122
+ //# sourceMappingURL=corrections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corrections.js","sourceRoot":"","sources":["../src/corrections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * The measurements of the validated prototype, in one place. These are the
3
+ * design system: change a number here and every diagram moves with it.
4
+ */
5
+ export declare const DIAGRAM_MARGIN = 16;
6
+ export declare const LANE_TOP = 44;
7
+ export declare const LANE_HEADER_BASELINE = 68;
8
+ export declare const LANE_PADDING_X = 16;
9
+ export declare const LANE_GAP = 20;
10
+ export declare const LANE_BOTTOM_PADDING = 20;
11
+ /**
12
+ * Every lane is the same width, and that width is a constant rather than
13
+ * anything derived from what the lanes hold.
14
+ *
15
+ * A lane's width decides where the lane after it starts, so a width drawn
16
+ * from content couples every column to the contents of the ones before it:
17
+ * adding one node with a long name to the first lane would slide every card
18
+ * in every later lane sideways, which is exactly the teleport a reviewer
19
+ * comparing two pushes must never be shown. The cost is that a lane holding
20
+ * something narrow is wider than it needs to be. Stability is worth more.
21
+ *
22
+ * Sized so that two cards sharing a row still each get a readable width.
23
+ */
24
+ export declare const LANE_CONTENT_WIDTH = 372;
25
+ export declare const LANE_RADIUS = 12;
26
+ export declare const LANE_LABEL_SIZE = 10;
27
+ export declare const LANE_LABEL_TRACKING = 0.12;
28
+ export declare const CONTENT_TOP = 92;
29
+ export declare const ROW_GAP = 52;
30
+ export declare const CARD_RADIUS = 10;
31
+ export declare const CARD_GAP_X = 12;
32
+ export declare const CARD_HEIGHT = 52;
33
+ export declare const CARD_HEIGHT_WITH_SUBTITLE = 62;
34
+ export declare const CARD_PADDING_X = 14;
35
+ export declare const ICON_CHIP_SIZE = 26;
36
+ export declare const ICON_CHIP_GAP = 10;
37
+ export declare const ICON_CHIP_RADIUS = 7;
38
+ /** Below this a card's title steps down a size to keep its room. */
39
+ export declare const ICON_MIN_CARD_WIDTH = 200;
40
+ export declare const TITLE_SIZE = 13;
41
+ export declare const TITLE_SIZE_SMALL = 11.5;
42
+ export declare const SUBTITLE_SIZE = 9.5;
43
+ export declare const BADGE_HEIGHT = 16;
44
+ export declare const BADGE_PADDING_X = 9;
45
+ export declare const BADGE_TEXT_SIZE = 8.5;
46
+ export declare const BADGE_TRACKING = 0.06;
47
+ export declare const BADGE_GAP = 6;
48
+ export declare const BADGE_RADIUS = 8;
49
+ /** How far the badge row rides above the top edge of the card it labels. */
50
+ export declare const BADGE_RISE = 8;
51
+ export declare const PILL_HEIGHT = 15;
52
+ export declare const PILL_PADDING_X = 8;
53
+ export declare const PILL_TEXT_SIZE = 9.5;
54
+ /** Two label pills never sit closer than this, in either direction. */
55
+ export declare const PILL_CLEARANCE = 2;
56
+ /**
57
+ * Routes travel in the gaps of the grid: vertical corridors beside lanes and
58
+ * horizontal bands between rows. Both gaps are physically 52px across — lane
59
+ * padding + lane gap + lane padding one way, ROW_GAP the other — and a track
60
+ * keeps this clearance from the cards on either side, leaving 40px of room.
61
+ */
62
+ export declare const TRACK_CLEARANCE = 6;
63
+ /**
64
+ * Neighbouring tracks in one gap sit this far apart at most; when a gap
65
+ * carries more traffic than the room allows, the pitch shrinks to fit. An
66
+ * added route therefore nudges its gap-mates proportionately — an accepted
67
+ * trade, and one that never moves a card.
68
+ */
69
+ export declare const TRACK_PITCH_MAX = 16;
70
+ /**
71
+ * And never closer than this: below it, parallel runs stop reading as
72
+ * separate lines. A gap asked to carry more traffic than the floor allows
73
+ * does not compress further — it widens instead, corridors pushing the lanes
74
+ * beside them apart and row gaps pushing the rows, in proportion to the
75
+ * traffic and to nothing else.
76
+ */
77
+ export declare const TRACK_PITCH_MIN = 10;
78
+ /** Step between neighbouring arrow ports along one card face. */
79
+ export declare const PORT_PITCH = 16;
80
+ /** Ports keep clear of the card's rounded corners. */
81
+ export declare const PORT_INSET = 14;
82
+ /**
83
+ * A turn's bend radius comes from the shorter of its two legs, capped here.
84
+ * Deriving it from the longer leg balloons a route with one short leg and one
85
+ * long one — the shape every corridor run has — clear out of its corridor.
86
+ */
87
+ export declare const BEND_RADIUS_MAX = 34;
88
+ /** One turn of the travelling pulse, and of the staggered train. */
89
+ export declare const PULSE_DURATION = 1.6;
90
+ export declare const HERO_PULSE_DURATION = 2.1;
91
+ export declare const HERO_PULSE_COUNT = 3;
92
+ /**
93
+ * A sequence animates one step at a time, in order, because that is the one
94
+ * thing a sequence has to say. Each pulse owns a slot of the cycle outright
95
+ * and crosses its arrow for the whole of it, so the drawing always has
96
+ * exactly one dot in flight — the next arrow lights as the last dot lands.
97
+ *
98
+ * This is how long one crossing takes when the flow is short enough to
99
+ * afford it: brisk enough to read as travelling, slow enough to follow.
100
+ */
101
+ export declare const FLOW_STEP_TRAVEL = 1.4;
102
+ /**
103
+ * A whole sequence should play through in one sitting. Past this the steps
104
+ * share the ceiling instead, which speeds up a long flow rather than asking
105
+ * a reader to wait a minute for its last arrow.
106
+ */
107
+ export declare const FLOW_CYCLE_MAX = 16;
108
+ /** How much of its own slot a pulse spends fading in, and again fading out. */
109
+ export declare const FLOW_PULSE_RAMP = 0.08;
110
+ /** More repeats than this and the arrows stop reading as separate calls. */
111
+ export declare const FLOW_MAX_PULSES_PER_MESSAGE = 3;
112
+ //# sourceMappingURL=design.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design.d.ts","sourceRoot":"","sources":["../src/design.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,cAAc,KAAK,CAAC;AAEjC,eAAO,MAAM,QAAQ,KAAK,CAAC;AAC3B,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,QAAQ,KAAK,CAAC;AAC3B,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,WAAW,KAAK,CAAC;AAC9B,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,eAAO,MAAM,WAAW,KAAK,CAAC;AAC9B,eAAO,MAAM,OAAO,KAAK,CAAC;AAE1B,eAAO,MAAM,WAAW,KAAK,CAAC;AAC9B,eAAO,MAAM,UAAU,KAAK,CAAC;AAC7B,eAAO,MAAM,WAAW,KAAK,CAAC;AAC9B,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAC5C,eAAO,MAAM,cAAc,KAAK,CAAC;AAEjC,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC,eAAO,MAAM,UAAU,KAAK,CAAC;AAC7B,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC,eAAO,MAAM,YAAY,KAAK,CAAC;AAC/B,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,eAAO,MAAM,eAAe,MAAM,CAAC;AACnC,eAAO,MAAM,cAAc,OAAO,CAAC;AACnC,eAAO,MAAM,SAAS,IAAI,CAAC;AAC3B,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,4EAA4E;AAC5E,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B,eAAO,MAAM,WAAW,KAAK,CAAC;AAC9B,eAAO,MAAM,cAAc,IAAI,CAAC;AAChC,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,uEAAuE;AACvE,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;;;GAKG;AACH,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC;;;;;GAKG;AACH,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,iEAAiE;AACjE,eAAO,MAAM,UAAU,KAAK,CAAC;AAC7B,sDAAsD;AACtD,eAAO,MAAM,UAAU,KAAK,CAAC;AAE7B;;;;GAIG;AACH,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,oEAAoE;AACpE,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC;;;;GAIG;AACH,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,+EAA+E;AAC/E,eAAO,MAAM,eAAe,OAAO,CAAC;AACpC,4EAA4E;AAC5E,eAAO,MAAM,2BAA2B,IAAI,CAAC"}
package/dist/design.js ADDED
@@ -0,0 +1,112 @@
1
+ /**
2
+ * The measurements of the validated prototype, in one place. These are the
3
+ * design system: change a number here and every diagram moves with it.
4
+ */
5
+ export const DIAGRAM_MARGIN = 16;
6
+ export const LANE_TOP = 44;
7
+ export const LANE_HEADER_BASELINE = 68;
8
+ export const LANE_PADDING_X = 16;
9
+ export const LANE_GAP = 20;
10
+ export const LANE_BOTTOM_PADDING = 20;
11
+ /**
12
+ * Every lane is the same width, and that width is a constant rather than
13
+ * anything derived from what the lanes hold.
14
+ *
15
+ * A lane's width decides where the lane after it starts, so a width drawn
16
+ * from content couples every column to the contents of the ones before it:
17
+ * adding one node with a long name to the first lane would slide every card
18
+ * in every later lane sideways, which is exactly the teleport a reviewer
19
+ * comparing two pushes must never be shown. The cost is that a lane holding
20
+ * something narrow is wider than it needs to be. Stability is worth more.
21
+ *
22
+ * Sized so that two cards sharing a row still each get a readable width.
23
+ */
24
+ export const LANE_CONTENT_WIDTH = 372;
25
+ export const LANE_RADIUS = 12;
26
+ export const LANE_LABEL_SIZE = 10;
27
+ export const LANE_LABEL_TRACKING = 0.12;
28
+ export const CONTENT_TOP = 92;
29
+ export const ROW_GAP = 52;
30
+ export const CARD_RADIUS = 10;
31
+ export const CARD_GAP_X = 12;
32
+ export const CARD_HEIGHT = 52;
33
+ export const CARD_HEIGHT_WITH_SUBTITLE = 62;
34
+ export const CARD_PADDING_X = 14;
35
+ export const ICON_CHIP_SIZE = 26;
36
+ export const ICON_CHIP_GAP = 10;
37
+ export const ICON_CHIP_RADIUS = 7;
38
+ /** Below this a card's title steps down a size to keep its room. */
39
+ export const ICON_MIN_CARD_WIDTH = 200;
40
+ export const TITLE_SIZE = 13;
41
+ export const TITLE_SIZE_SMALL = 11.5;
42
+ export const SUBTITLE_SIZE = 9.5;
43
+ export const BADGE_HEIGHT = 16;
44
+ export const BADGE_PADDING_X = 9;
45
+ export const BADGE_TEXT_SIZE = 8.5;
46
+ export const BADGE_TRACKING = 0.06;
47
+ export const BADGE_GAP = 6;
48
+ export const BADGE_RADIUS = 8;
49
+ /** How far the badge row rides above the top edge of the card it labels. */
50
+ export const BADGE_RISE = 8;
51
+ export const PILL_HEIGHT = 15;
52
+ export const PILL_PADDING_X = 8;
53
+ export const PILL_TEXT_SIZE = 9.5;
54
+ /** Two label pills never sit closer than this, in either direction. */
55
+ export const PILL_CLEARANCE = 2;
56
+ /**
57
+ * Routes travel in the gaps of the grid: vertical corridors beside lanes and
58
+ * horizontal bands between rows. Both gaps are physically 52px across — lane
59
+ * padding + lane gap + lane padding one way, ROW_GAP the other — and a track
60
+ * keeps this clearance from the cards on either side, leaving 40px of room.
61
+ */
62
+ export const TRACK_CLEARANCE = 6;
63
+ /**
64
+ * Neighbouring tracks in one gap sit this far apart at most; when a gap
65
+ * carries more traffic than the room allows, the pitch shrinks to fit. An
66
+ * added route therefore nudges its gap-mates proportionately — an accepted
67
+ * trade, and one that never moves a card.
68
+ */
69
+ export const TRACK_PITCH_MAX = 16;
70
+ /**
71
+ * And never closer than this: below it, parallel runs stop reading as
72
+ * separate lines. A gap asked to carry more traffic than the floor allows
73
+ * does not compress further — it widens instead, corridors pushing the lanes
74
+ * beside them apart and row gaps pushing the rows, in proportion to the
75
+ * traffic and to nothing else.
76
+ */
77
+ export const TRACK_PITCH_MIN = 10;
78
+ /** Step between neighbouring arrow ports along one card face. */
79
+ export const PORT_PITCH = 16;
80
+ /** Ports keep clear of the card's rounded corners. */
81
+ export const PORT_INSET = 14;
82
+ /**
83
+ * A turn's bend radius comes from the shorter of its two legs, capped here.
84
+ * Deriving it from the longer leg balloons a route with one short leg and one
85
+ * long one — the shape every corridor run has — clear out of its corridor.
86
+ */
87
+ export const BEND_RADIUS_MAX = 34;
88
+ /** One turn of the travelling pulse, and of the staggered train. */
89
+ export const PULSE_DURATION = 1.6;
90
+ export const HERO_PULSE_DURATION = 2.1;
91
+ export const HERO_PULSE_COUNT = 3;
92
+ /**
93
+ * A sequence animates one step at a time, in order, because that is the one
94
+ * thing a sequence has to say. Each pulse owns a slot of the cycle outright
95
+ * and crosses its arrow for the whole of it, so the drawing always has
96
+ * exactly one dot in flight — the next arrow lights as the last dot lands.
97
+ *
98
+ * This is how long one crossing takes when the flow is short enough to
99
+ * afford it: brisk enough to read as travelling, slow enough to follow.
100
+ */
101
+ export const FLOW_STEP_TRAVEL = 1.4;
102
+ /**
103
+ * A whole sequence should play through in one sitting. Past this the steps
104
+ * share the ceiling instead, which speeds up a long flow rather than asking
105
+ * a reader to wait a minute for its last arrow.
106
+ */
107
+ export const FLOW_CYCLE_MAX = 16;
108
+ /** How much of its own slot a pulse spends fading in, and again fading out. */
109
+ export const FLOW_PULSE_RAMP = 0.08;
110
+ /** More repeats than this and the arrows stop reading as separate calls. */
111
+ export const FLOW_MAX_PULSES_PER_MESSAGE = 3;
112
+ //# sourceMappingURL=design.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design.js","sourceRoot":"","sources":["../src/design.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Codes are the stable half of a failure; the message is for a human. Every
3
+ * one of these describes a document the renderer cannot draw, never an
4
+ * internal fault.
5
+ */
6
+ export type RenderErrorCode = "UNKNOWN_VIEW" | "LENS_NOT_DECLARED" | "NOTHING_TO_RENDER" | "NO_FLOW_IN_SCOPE" | "TOO_MANY_ASSETS";
7
+ export declare class PrLensRenderError extends Error {
8
+ readonly code: RenderErrorCode;
9
+ constructor(code: RenderErrorCode, message: string);
10
+ }
11
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,mBAAmB,GACnB,mBAAmB,GACnB,kBAAkB,GAClB,iBAAiB,CAAC;AAEtB,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAE/B,YAAY,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAIjD;CACF"}
package/dist/errors.js ADDED
@@ -0,0 +1,9 @@
1
+ export class PrLensRenderError extends Error {
2
+ code;
3
+ constructor(code, message) {
4
+ super(message);
5
+ this.name = "PrLensRenderError";
6
+ this.code = code;
7
+ }
8
+ }
9
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAkB;IAE/B,YAAY,IAAqB,EAAE,OAAe;QAChD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ export type Point = {
2
+ x: number;
3
+ y: number;
4
+ };
5
+ export type Box = {
6
+ x: number;
7
+ y: number;
8
+ width: number;
9
+ height: number;
10
+ };
11
+ /** Which face of a box a line meets. */
12
+ export type Side = "top" | "right" | "bottom" | "left";
13
+ /**
14
+ * Every coordinate the renderer writes goes through here. Floating point
15
+ * arithmetic that differs in the last bit would otherwise change the bytes of
16
+ * the document without changing the picture, and the render hash with it.
17
+ */
18
+ export declare const coord: (value: number) => string;
19
+ export declare const boxCentre: (box: Box) => Point;
20
+ //# sourceMappingURL=geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7C,MAAM,MAAM,GAAG,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1E,wCAAwC;AACxC,MAAM,MAAM,IAAI,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEvD;;;;GAIG;AACH,eAAO,MAAM,KAAK,UAAW,MAAM,KAAG,MAIrC,CAAC;AAEF,eAAO,MAAM,SAAS,QAAS,GAAG,KAAG,KAGnC,CAAC"}