@coldtea/pr-lens-renderer 0.4.1 → 0.5.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 +15 -0
- package/dist/glob.d.ts.map +1 -1
- package/dist/glob.js +72 -9
- package/dist/glob.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +11 -3
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +10 -1
- package/dist/manifest.js.map +1 -1
- package/dist/render-all.d.ts +35 -0
- package/dist/render-all.d.ts.map +1 -0
- package/dist/render-all.js +110 -0
- package/dist/render-all.js.map +1 -0
- package/dist/render.d.ts +4 -31
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +5 -75
- package/dist/render.js.map +1 -1
- package/dist/svg/document.d.ts +8 -0
- package/dist/svg/document.d.ts.map +1 -1
- package/dist/svg/document.js +3 -2
- package/dist/svg/document.js.map +1 -1
- package/dist/theme.d.ts +2 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +1 -0
- package/dist/theme.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/walkthrough/camera.d.ts +43 -0
- package/dist/walkthrough/camera.d.ts.map +1 -0
- package/dist/walkthrough/camera.js +101 -0
- package/dist/walkthrough/camera.js.map +1 -0
- package/dist/walkthrough/caption.d.ts +5 -0
- package/dist/walkthrough/caption.d.ts.map +1 -0
- package/dist/walkthrough/caption.js +36 -0
- package/dist/walkthrough/caption.js.map +1 -0
- package/dist/walkthrough/embed.d.ts +31 -0
- package/dist/walkthrough/embed.d.ts.map +1 -0
- package/dist/walkthrough/embed.js +297 -0
- package/dist/walkthrough/embed.js.map +1 -0
- package/dist/walkthrough/index.d.ts +8 -0
- package/dist/walkthrough/index.d.ts.map +1 -0
- package/dist/walkthrough/index.js +6 -0
- package/dist/walkthrough/index.js.map +1 -0
- package/dist/walkthrough/layout.d.ts +28 -0
- package/dist/walkthrough/layout.d.ts.map +1 -0
- package/dist/walkthrough/layout.js +31 -0
- package/dist/walkthrough/layout.js.map +1 -0
- package/dist/walkthrough/nest.d.ts +4 -0
- package/dist/walkthrough/nest.d.ts.map +1 -0
- package/dist/walkthrough/nest.js +4 -0
- package/dist/walkthrough/nest.js.map +1 -0
- package/dist/walkthrough/resolve.d.ts +45 -0
- package/dist/walkthrough/resolve.d.ts.map +1 -0
- package/dist/walkthrough/resolve.js +189 -0
- package/dist/walkthrough/resolve.js.map +1 -0
- package/dist/walkthrough/tile-ids.d.ts +8 -0
- package/dist/walkthrough/tile-ids.d.ts.map +1 -0
- package/dist/walkthrough/tile-ids.js +16 -0
- package/dist/walkthrough/tile-ids.js.map +1 -0
- package/dist/walkthrough/tiles.d.ts +15 -0
- package/dist/walkthrough/tiles.d.ts.map +1 -0
- package/dist/walkthrough/tiles.js +80 -0
- package/dist/walkthrough/tiles.js.map +1 -0
- package/package.json +7 -3
- package/src/glob.ts +76 -11
- package/src/index.ts +23 -6
- package/src/manifest.ts +20 -3
- package/src/render-all.ts +195 -0
- package/src/render.ts +8 -116
- package/src/svg/document.ts +3 -2
- package/src/theme.ts +4 -0
- package/src/version.ts +1 -1
- package/src/walkthrough/camera.ts +142 -0
- package/src/walkthrough/caption.ts +35 -0
- package/src/walkthrough/embed.ts +436 -0
- package/src/walkthrough/index.ts +42 -0
- package/src/walkthrough/layout.ts +46 -0
- package/src/walkthrough/nest.ts +6 -0
- package/src/walkthrough/resolve.ts +268 -0
- package/src/walkthrough/tile-ids.ts +17 -0
- package/src/walkthrough/tiles.ts +106 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { assertNever } from "@coldtea/pr-lens-schema";
|
|
2
|
+
import { inflate, union } from "../bounds.js";
|
|
3
|
+
import { flattenViews } from "../scope.js";
|
|
4
|
+
import { tileIdForFlow, tileIdForView } from "./tile-ids.js";
|
|
5
|
+
/** Air around a focus. Message rows sit 38 units apart, so much more puts the rim over the row above. */
|
|
6
|
+
const FOCUS_PAD = 16;
|
|
7
|
+
/** Resolves all of the walkthrough or none of it, collecting every issue in step order. */
|
|
8
|
+
export function resolveWalkthrough(doc, tiles) {
|
|
9
|
+
if (doc.walkthrough === undefined)
|
|
10
|
+
return { type: "absent" };
|
|
11
|
+
const steps = [];
|
|
12
|
+
const issues = [];
|
|
13
|
+
for (const step of doc.walkthrough.steps) {
|
|
14
|
+
const resolved = resolveStep(doc, step, tiles);
|
|
15
|
+
switch (resolved.type) {
|
|
16
|
+
case "step":
|
|
17
|
+
steps.push(resolved.step);
|
|
18
|
+
break;
|
|
19
|
+
case "issues":
|
|
20
|
+
issues.push(...resolved.issues);
|
|
21
|
+
break;
|
|
22
|
+
default:
|
|
23
|
+
return assertNever(resolved, "Unhandled step resolution");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return issues.length > 0 ? { type: "unresolvable", issues } : { type: "resolved", steps };
|
|
27
|
+
}
|
|
28
|
+
/** One issue as a sentence. */
|
|
29
|
+
const says = (issue) => `Step "${issue.stepId}" ${issue.detail}.`;
|
|
30
|
+
/** Copy for a refused push: the first wrong step by name, and a count of the rest. */
|
|
31
|
+
export function walkthroughRefusal(issues) {
|
|
32
|
+
const first = issues[0];
|
|
33
|
+
if (first === undefined)
|
|
34
|
+
return "This document's walkthrough does not fit the diagrams it draws";
|
|
35
|
+
const elsewhere = new Set(issues.map((issue) => issue.stepId));
|
|
36
|
+
elsewhere.delete(first.stepId);
|
|
37
|
+
const rest = elsewhere.size === 0
|
|
38
|
+
? ""
|
|
39
|
+
: elsewhere.size === 1
|
|
40
|
+
? " One other step has the same trouble."
|
|
41
|
+
: ` ${elsewhere.size} other steps have the same trouble.`;
|
|
42
|
+
return `This document's walkthrough does not fit the diagrams it draws. ${says(first)}${rest}`;
|
|
43
|
+
}
|
|
44
|
+
function resolveStep(doc, step, tiles) {
|
|
45
|
+
const choice = step.stage ?? { kind: "opening" };
|
|
46
|
+
const staged = stageTile(doc, choice, tiles);
|
|
47
|
+
switch (staged.type) {
|
|
48
|
+
case "off_canvas":
|
|
49
|
+
return { type: "issues", issues: [{ code: "STAGE_NOT_ON_CANVAS", stepId: step.id, detail: staged.detail }] };
|
|
50
|
+
case "on_canvas":
|
|
51
|
+
break;
|
|
52
|
+
default:
|
|
53
|
+
return assertNever(staged, "Unhandled staged tile");
|
|
54
|
+
}
|
|
55
|
+
const focus = resolveFocus(doc, step, choice, staged.tile.atlas);
|
|
56
|
+
switch (focus.type) {
|
|
57
|
+
case "focus":
|
|
58
|
+
return {
|
|
59
|
+
type: "step",
|
|
60
|
+
step: { id: step.id, heading: step.heading, body: step.body, tileId: staged.tile.id, focus: focus.focus },
|
|
61
|
+
};
|
|
62
|
+
case "issues":
|
|
63
|
+
return focus;
|
|
64
|
+
default:
|
|
65
|
+
return assertNever(focus, "Unhandled focus resolution");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function tileForStage(doc, stage, tiles) {
|
|
69
|
+
const staged = stageTile(doc, stage ?? { kind: "opening" }, tiles);
|
|
70
|
+
switch (staged.type) {
|
|
71
|
+
case "on_canvas":
|
|
72
|
+
return tiles.find((tile) => tile.id === staged.tile.id);
|
|
73
|
+
case "off_canvas":
|
|
74
|
+
return undefined;
|
|
75
|
+
default:
|
|
76
|
+
return assertNever(staged, "Unhandled staged tile");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** A flow is a tile only when there are no data-flow views; otherwise the first view drawing it is the stage. */
|
|
80
|
+
function stageTile(doc, choice, tiles) {
|
|
81
|
+
switch (choice.kind) {
|
|
82
|
+
case "opening": {
|
|
83
|
+
const opening = tiles.find((tile) => tile.hero);
|
|
84
|
+
return opening === undefined
|
|
85
|
+
? { type: "off_canvas", detail: "has no stage of its own, and this document draws no opening diagram" }
|
|
86
|
+
: { type: "on_canvas", tile: opening };
|
|
87
|
+
}
|
|
88
|
+
case "view":
|
|
89
|
+
return named(tiles, [tileIdForView(choice.view)], `plays over view "${choice.view}", which the canvas does not draw`);
|
|
90
|
+
case "flow":
|
|
91
|
+
return named(tiles, [tileIdForFlow(choice.flow), ...viewTilesDrawing(doc, choice.flow)], `plays over flow "${choice.flow}", which the canvas does not draw`);
|
|
92
|
+
default:
|
|
93
|
+
return assertNever(choice, "Unhandled stage");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** The first of these tiles in strip order, not in the order asked for. */
|
|
97
|
+
function named(tiles, ids, detail) {
|
|
98
|
+
const wanted = new Set(ids);
|
|
99
|
+
const tile = tiles.find((candidate) => wanted.has(candidate.id));
|
|
100
|
+
return tile === undefined ? { type: "off_canvas", detail } : { type: "on_canvas", tile };
|
|
101
|
+
}
|
|
102
|
+
const scopeTakesFlow = (scope, flowId) => {
|
|
103
|
+
switch (scope.kind) {
|
|
104
|
+
case "all":
|
|
105
|
+
return true;
|
|
106
|
+
case "selection":
|
|
107
|
+
return scope.flows.includes(flowId);
|
|
108
|
+
default:
|
|
109
|
+
return assertNever(scope, "Unhandled view scope");
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const viewTilesDrawing = (doc, flowId) => flattenViews(doc.views)
|
|
113
|
+
.filter((view) => view.lens === "data-flow" && scopeTakesFlow(view.scope, flowId))
|
|
114
|
+
.map((view) => tileIdForView(view.id));
|
|
115
|
+
function resolveFocus(doc, step, choice, atlas) {
|
|
116
|
+
switch (step.focus.kind) {
|
|
117
|
+
case "all":
|
|
118
|
+
return { type: "focus", focus: { kind: "whole" } };
|
|
119
|
+
case "selection":
|
|
120
|
+
return atlas === undefined
|
|
121
|
+
? {
|
|
122
|
+
type: "issues",
|
|
123
|
+
issues: [
|
|
124
|
+
{
|
|
125
|
+
code: "ATLAS_MISSING",
|
|
126
|
+
stepId: step.id,
|
|
127
|
+
detail: "plays over a diagram drawn without the geometry a walkthrough needs",
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
}
|
|
131
|
+
: selectionRect(doc, step.id, step.focus, choice, atlas);
|
|
132
|
+
default:
|
|
133
|
+
return assertNever(step.focus, "Unhandled step focus");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** The padded union of everything a step names. A member never drawn is an issue, not a skip. */
|
|
137
|
+
function selectionRect(doc, stepId, selection, choice, atlas) {
|
|
138
|
+
const boxes = [];
|
|
139
|
+
const issues = [];
|
|
140
|
+
const take = (kind, id, box) => {
|
|
141
|
+
if (box === undefined) {
|
|
142
|
+
issues.push({
|
|
143
|
+
code: "FOCUS_NOT_DRAWN",
|
|
144
|
+
stepId,
|
|
145
|
+
detail: `focuses ${kind} "${id}", which the diagram it plays over does not draw`,
|
|
146
|
+
});
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
boxes.push(box);
|
|
150
|
+
};
|
|
151
|
+
for (const id of selection.lanes)
|
|
152
|
+
take("lane", id, atlas.lanes[id]);
|
|
153
|
+
for (const id of selection.nodes)
|
|
154
|
+
take("node", id, atlas.nodes[id]);
|
|
155
|
+
for (const id of selection.edges)
|
|
156
|
+
take("edge", id, atlas.edges[id]);
|
|
157
|
+
for (const id of selection.messages)
|
|
158
|
+
take("flow step", id, messageBox(doc, choice, atlas, id));
|
|
159
|
+
for (const id of selection.tables)
|
|
160
|
+
take("table", id, atlas.tables[id]);
|
|
161
|
+
if (issues.length > 0)
|
|
162
|
+
return { type: "issues", issues };
|
|
163
|
+
// A selection that names nothing does not parse, so one with no issues left has at least one box.
|
|
164
|
+
const covered = union(boxes);
|
|
165
|
+
if (covered === undefined)
|
|
166
|
+
throw new Error("a selection with nothing drawn is reported, not framed");
|
|
167
|
+
return { type: "focus", focus: { kind: "region", rect: inflate(covered, FOCUS_PAD) } };
|
|
168
|
+
}
|
|
169
|
+
/** A flow step's id is unique only inside its flow, so a view stage asks the document's flows in order. */
|
|
170
|
+
function messageBox(doc, choice, atlas, messageId) {
|
|
171
|
+
for (const flowId of flowsToAsk(doc, choice)) {
|
|
172
|
+
const box = atlas.messages[flowId]?.[messageId];
|
|
173
|
+
if (box !== undefined)
|
|
174
|
+
return box;
|
|
175
|
+
}
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
const flowsToAsk = (doc, choice) => {
|
|
179
|
+
switch (choice.kind) {
|
|
180
|
+
case "flow":
|
|
181
|
+
return [choice.flow];
|
|
182
|
+
case "opening":
|
|
183
|
+
case "view":
|
|
184
|
+
return doc.flows.map((flow) => flow.id);
|
|
185
|
+
default:
|
|
186
|
+
return assertNever(choice, "Unhandled stage");
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/walkthrough/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { StepStage } from "@coldtea/pr-lens-schema";
|
|
2
|
+
export declare const tileIdForView: (viewId: string) => string;
|
|
3
|
+
export declare const tileIdForFlow: (flowId: string) => string;
|
|
4
|
+
export declare const WHOLE_MAP_TILE_ID = "lens:architecture";
|
|
5
|
+
export declare const WHOLE_MODEL_TILE_ID = "lens:data-model";
|
|
6
|
+
/** The stage a tile stands for. A whole lens drawn without a view has none. */
|
|
7
|
+
export declare function stageOfTile(tileId: string): StepStage | null;
|
|
8
|
+
//# sourceMappingURL=tile-ids.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tile-ids.d.ts","sourceRoot":"","sources":["../../src/walkthrough/tile-ids.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAMzD,eAAO,MAAM,aAAa,WAAY,MAAM,KAAG,MAAmC,CAAC;AACnF,eAAO,MAAM,aAAa,WAAY,MAAM,KAAG,MAAmC,CAAC;AACnF,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AACrD,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAI5D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** The one spelling of every tile id. Kept apart from the drawing so a browser can read one back. */
|
|
2
|
+
const VIEW_PREFIX = "view:";
|
|
3
|
+
const FLOW_PREFIX = "flow:";
|
|
4
|
+
export const tileIdForView = (viewId) => `${VIEW_PREFIX}${viewId}`;
|
|
5
|
+
export const tileIdForFlow = (flowId) => `${FLOW_PREFIX}${flowId}`;
|
|
6
|
+
export const WHOLE_MAP_TILE_ID = "lens:architecture";
|
|
7
|
+
export const WHOLE_MODEL_TILE_ID = "lens:data-model";
|
|
8
|
+
/** The stage a tile stands for. A whole lens drawn without a view has none. */
|
|
9
|
+
export function stageOfTile(tileId) {
|
|
10
|
+
if (tileId.startsWith(VIEW_PREFIX))
|
|
11
|
+
return { kind: "view", view: tileId.slice(VIEW_PREFIX.length) };
|
|
12
|
+
if (tileId.startsWith(FLOW_PREFIX))
|
|
13
|
+
return { kind: "flow", flow: tileId.slice(FLOW_PREFIX.length) };
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=tile-ids.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tile-ids.js","sourceRoot":"","sources":["../../src/walkthrough/tile-ids.ts"],"names":[],"mappings":"AAEA,qGAAqG;AACrG,MAAM,WAAW,GAAG,OAAO,CAAC;AAC5B,MAAM,WAAW,GAAG,OAAO,CAAC;AAE5B,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,GAAG,WAAW,GAAG,MAAM,EAAE,CAAC;AACnF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,GAAG,WAAW,GAAG,MAAM,EAAE,CAAC;AACnF,MAAM,CAAC,MAAM,iBAAiB,GAAG,mBAAmB,CAAC;AACrD,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAErD,+EAA+E;AAC/E,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,IAAI,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;IACpG,IAAI,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;IACpG,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Flow, GraphDoc, Lens } from "@coldtea/pr-lens-schema";
|
|
2
|
+
import { type RenderedSvg } from "../render.js";
|
|
3
|
+
import type { Theme } from "../theme.js";
|
|
4
|
+
/** The strip's tiles in order: hero, other architecture views, data-flow views, data-model views. */
|
|
5
|
+
export type TilePlan = {
|
|
6
|
+
id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
lens: Lens;
|
|
9
|
+
hero: boolean;
|
|
10
|
+
draw: (theme: Theme) => RenderedSvg;
|
|
11
|
+
};
|
|
12
|
+
export declare function planTiles(doc: GraphDoc): TilePlan[];
|
|
13
|
+
/** One sequence on its own. The renderer narrows to a flow only through a view scoped to it. */
|
|
14
|
+
export declare function renderFlow(doc: GraphDoc, flow: Flow, theme: Theme): RenderedSvg;
|
|
15
|
+
//# sourceMappingURL=tiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiles.d.ts","sourceRoot":"","sources":["../../src/walkthrough/tiles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAQ,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGzC,qGAAqG;AACrG,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,WAAW,CAAC;CACrC,CAAC;AAmCF,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,GAAG,QAAQ,EAAE,CAkCnD;AAKD,gGAAgG;AAChG,wBAAgB,UAAU,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG,WAAW,CAiB/E"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { render } from "../render.js";
|
|
2
|
+
import { flattenViews } from "../scope.js";
|
|
3
|
+
import { tileIdForFlow, tileIdForView, WHOLE_MAP_TILE_ID, WHOLE_MODEL_TILE_ID } from "./tile-ids.js";
|
|
4
|
+
const viewTile = (doc, view, hero) => ({
|
|
5
|
+
id: tileIdForView(view.id),
|
|
6
|
+
title: view.title,
|
|
7
|
+
lens: view.lens,
|
|
8
|
+
hero,
|
|
9
|
+
draw: (theme) => render(doc, { lens: view.lens, theme, view: view.id }),
|
|
10
|
+
});
|
|
11
|
+
const wholeMapTile = (doc) => ({
|
|
12
|
+
id: WHOLE_MAP_TILE_ID,
|
|
13
|
+
title: doc.title,
|
|
14
|
+
lens: "architecture",
|
|
15
|
+
hero: true,
|
|
16
|
+
draw: (theme) => render(doc, { lens: "architecture", theme }),
|
|
17
|
+
});
|
|
18
|
+
const flowTiles = (doc) => doc.flows.map((flow) => ({
|
|
19
|
+
id: tileIdForFlow(flow.id),
|
|
20
|
+
title: flow.title,
|
|
21
|
+
lens: "data-flow",
|
|
22
|
+
hero: false,
|
|
23
|
+
draw: (theme) => renderFlow(doc, flow, theme),
|
|
24
|
+
}));
|
|
25
|
+
const wholeModelTile = (doc) => ({
|
|
26
|
+
id: WHOLE_MODEL_TILE_ID,
|
|
27
|
+
title: doc.title,
|
|
28
|
+
lens: "data-model",
|
|
29
|
+
hero: false,
|
|
30
|
+
draw: (theme) => render(doc, { lens: "data-model", theme }),
|
|
31
|
+
});
|
|
32
|
+
export function planTiles(doc) {
|
|
33
|
+
const placed = flattenViews(doc.views);
|
|
34
|
+
const architecture = placed.filter((view) => view.lens === "architecture");
|
|
35
|
+
const heroIndex = Math.max(architecture.findIndex((view) => view.defaultOpen), 0);
|
|
36
|
+
const architectureTiles = architecture.length > 0
|
|
37
|
+
? [
|
|
38
|
+
...architecture.slice(heroIndex, heroIndex + 1).map((view) => viewTile(doc, view, true)),
|
|
39
|
+
...architecture.filter((_, index) => index !== heroIndex).map((view) => viewTile(doc, view, false)),
|
|
40
|
+
]
|
|
41
|
+
: doc.lenses.includes("architecture")
|
|
42
|
+
? [wholeMapTile(doc)]
|
|
43
|
+
: [];
|
|
44
|
+
const dataFlow = placed.filter((view) => view.lens === "data-flow");
|
|
45
|
+
const dataFlowTiles = dataFlow.length > 0
|
|
46
|
+
? dataFlow.map((view) => viewTile(doc, view, false))
|
|
47
|
+
: doc.lenses.includes("data-flow")
|
|
48
|
+
? flowTiles(doc)
|
|
49
|
+
: [];
|
|
50
|
+
const dataModel = placed.filter((view) => view.lens === "data-model");
|
|
51
|
+
const dataModelTiles = dataModel.length > 0
|
|
52
|
+
? dataModel.map((view) => viewTile(doc, view, false))
|
|
53
|
+
: doc.lenses.includes("data-model") && doc.dataModel !== undefined
|
|
54
|
+
? [wholeModelTile(doc)]
|
|
55
|
+
: [];
|
|
56
|
+
const tiles = [...architectureTiles, ...dataFlowTiles, ...dataModelTiles];
|
|
57
|
+
// A step without a stage plays over whatever leads the strip.
|
|
58
|
+
return tiles.map((tile, index) => ({ ...tile, hero: index === 0 }));
|
|
59
|
+
}
|
|
60
|
+
/** The only view on the copy it is attached to, so a fixed id cannot collide. */
|
|
61
|
+
const FLOW_VIEW_ID = "pr-lens-flow";
|
|
62
|
+
/** One sequence on its own. The renderer narrows to a flow only through a view scoped to it. */
|
|
63
|
+
export function renderFlow(doc, flow, theme) {
|
|
64
|
+
const scoped = {
|
|
65
|
+
...doc,
|
|
66
|
+
views: [
|
|
67
|
+
{
|
|
68
|
+
id: FLOW_VIEW_ID,
|
|
69
|
+
title: flow.title,
|
|
70
|
+
lens: "data-flow",
|
|
71
|
+
...(flow.summary === undefined ? {} : { summary: flow.summary }),
|
|
72
|
+
scope: { kind: "selection", lanes: [], nodes: [], edges: [], flows: [flow.id], tables: [] },
|
|
73
|
+
defaultOpen: false,
|
|
74
|
+
children: [],
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
return render(scoped, { lens: "data-flow", theme, view: FLOW_VIEW_ID });
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=tiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiles.js","sourceRoot":"","sources":["../../src/walkthrough/tiles.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coldtea/pr-lens-renderer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "The PR Lens renderer: a schema-valid graph document in, a self-contained animated SVG out.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Coldtea AI",
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
"types": "./dist/index.d.ts",
|
|
26
26
|
"default": "./dist/index.js"
|
|
27
27
|
},
|
|
28
|
+
"./walkthrough": {
|
|
29
|
+
"types": "./dist/walkthrough/index.d.ts",
|
|
30
|
+
"default": "./dist/walkthrough/index.js"
|
|
31
|
+
},
|
|
28
32
|
"./package.json": "./package.json"
|
|
29
33
|
},
|
|
30
34
|
"files": [
|
|
@@ -40,7 +44,7 @@
|
|
|
40
44
|
"node": ">=20.11"
|
|
41
45
|
},
|
|
42
46
|
"dependencies": {
|
|
43
|
-
"@coldtea/pr-lens-schema": "0.
|
|
47
|
+
"@coldtea/pr-lens-schema": "0.10.0"
|
|
44
48
|
},
|
|
45
49
|
"devDependencies": {
|
|
46
50
|
"@types/node": "^20.19.0",
|
|
@@ -48,7 +52,7 @@
|
|
|
48
52
|
"vitest": "4.1.12"
|
|
49
53
|
},
|
|
50
54
|
"scripts": {
|
|
51
|
-
"build": "
|
|
55
|
+
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json",
|
|
52
56
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
53
57
|
"test": "vitest run",
|
|
54
58
|
"test:watch": "vitest"
|
package/src/glob.ts
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
import { assertNever } from "@coldtea/pr-lens-schema";
|
|
2
|
+
|
|
3
|
+
type GlobToken =
|
|
4
|
+
| { readonly kind: "crossDir" }
|
|
5
|
+
| { readonly kind: "cross" }
|
|
6
|
+
| { readonly kind: "star" }
|
|
7
|
+
| { readonly kind: "any" }
|
|
8
|
+
| { readonly kind: "char"; readonly value: string };
|
|
9
|
+
|
|
10
|
+
const tokenize = (pattern: string): readonly GlobToken[] => {
|
|
11
|
+
const tokens: GlobToken[] = [];
|
|
12
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
13
|
+
const ch = pattern[i]!;
|
|
14
|
+
if (
|
|
15
|
+
ch === "*" &&
|
|
16
|
+
pattern[i + 1] === "*" &&
|
|
17
|
+
pattern[i + 2] === "/" &&
|
|
18
|
+
(i === 0 || pattern[i - 1] === "/")
|
|
19
|
+
) {
|
|
20
|
+
tokens.push({ kind: "crossDir" });
|
|
21
|
+
i += 2;
|
|
22
|
+
} else if (ch === "*" && pattern[i + 1] === "*") {
|
|
23
|
+
tokens.push({ kind: "cross" });
|
|
24
|
+
i += 1;
|
|
25
|
+
} else if (ch === "*") {
|
|
26
|
+
tokens.push({ kind: "star" });
|
|
27
|
+
} else if (ch === "?") {
|
|
28
|
+
tokens.push({ kind: "any" });
|
|
29
|
+
} else {
|
|
30
|
+
tokens.push({ kind: "char", value: ch });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return tokens;
|
|
34
|
+
};
|
|
2
35
|
|
|
3
36
|
/**
|
|
4
37
|
* Path matching for config selectors, with the subset of glob a person
|
|
@@ -6,15 +39,47 @@ const escapeRegExp = (value: string): string => value.replace(/[.*+?^${}()|[\]\\
|
|
|
6
39
|
* not. Every other character is literal.
|
|
7
40
|
*/
|
|
8
41
|
export const matchesGlob = (pattern: string, path: string): boolean => {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
42
|
+
const n = path.length;
|
|
43
|
+
const reachable = new Uint8Array(n + 1);
|
|
44
|
+
reachable[0] = 1;
|
|
45
|
+
|
|
46
|
+
for (const token of tokenize(pattern)) {
|
|
47
|
+
switch (token.kind) {
|
|
48
|
+
case "crossDir": {
|
|
49
|
+
const first = reachable.indexOf(1);
|
|
50
|
+
if (first !== -1) {
|
|
51
|
+
for (let j = first + 1; j <= n; j += 1) {
|
|
52
|
+
if (path[j - 1] === "/") reachable[j] = 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
case "cross":
|
|
58
|
+
for (let j = 1; j <= n; j += 1) {
|
|
59
|
+
if (reachable[j - 1]) reachable[j] = 1;
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
case "star":
|
|
63
|
+
for (let j = 1; j <= n; j += 1) {
|
|
64
|
+
if (path[j - 1] !== "/" && reachable[j - 1]) reachable[j] = 1;
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
case "any":
|
|
68
|
+
for (let j = n; j >= 1; j -= 1) {
|
|
69
|
+
reachable[j] = path[j - 1] !== "/" && reachable[j - 1] ? 1 : 0;
|
|
70
|
+
}
|
|
71
|
+
reachable[0] = 0;
|
|
72
|
+
break;
|
|
73
|
+
case "char":
|
|
74
|
+
for (let j = n; j >= 1; j -= 1) {
|
|
75
|
+
reachable[j] = path[j - 1] === token.value && reachable[j - 1] ? 1 : 0;
|
|
76
|
+
}
|
|
77
|
+
reachable[0] = 0;
|
|
78
|
+
break;
|
|
79
|
+
default:
|
|
80
|
+
return assertNever(token);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
18
83
|
|
|
19
|
-
return
|
|
84
|
+
return reachable[n] === 1;
|
|
20
85
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
export { RENDERER_NAME, RENDERER_VERSION } from "./version.js";
|
|
2
2
|
|
|
3
|
+
export { render, type RenderedSvg, type RenderOptions } from "./render.js";
|
|
4
|
+
|
|
3
5
|
export {
|
|
4
|
-
render,
|
|
5
6
|
renderAll,
|
|
6
7
|
type RenderAllOptions,
|
|
7
|
-
type RenderThemes,
|
|
8
8
|
type RenderAllResult,
|
|
9
9
|
type RenderedAsset,
|
|
10
|
-
type
|
|
11
|
-
type
|
|
12
|
-
|
|
10
|
+
type RenderedWalkthrough,
|
|
11
|
+
type RenderedWalkthroughs,
|
|
12
|
+
type RenderThemes,
|
|
13
|
+
} from "./render-all.js";
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
EMBED_WIDTH,
|
|
17
|
+
renderWalkthroughEmbed,
|
|
18
|
+
walkthroughLabel,
|
|
19
|
+
type WalkthroughEmbed,
|
|
20
|
+
type WalkthroughEmbedOptions,
|
|
21
|
+
type WalkthroughEmbedResult,
|
|
22
|
+
} from "./walkthrough/embed.js";
|
|
23
|
+
|
|
24
|
+
export { planTiles, renderFlow, type TilePlan } from "./walkthrough/tiles.js";
|
|
25
|
+
|
|
26
|
+
export * from "./walkthrough/index.js";
|
|
13
27
|
|
|
14
28
|
export { emptyAtlas, type RenderAtlas } from "./atlas.js";
|
|
15
29
|
|
|
@@ -17,9 +31,10 @@ export { PrLensRenderError, type RenderErrorCode } from "./errors.js";
|
|
|
17
31
|
|
|
18
32
|
export type { Box } from "./geometry.js";
|
|
19
33
|
|
|
20
|
-
export { paletteFor, THEMES, THEME_PAIR, type Palette, type Theme } from "./theme.js";
|
|
34
|
+
export { isPairTheme, paletteFor, THEMES, THEME_PAIR, type PairTheme, type Palette, type Theme } from "./theme.js";
|
|
21
35
|
|
|
22
36
|
export {
|
|
37
|
+
assetIdentity,
|
|
23
38
|
buildManifest,
|
|
24
39
|
canonicalJson,
|
|
25
40
|
contentHash,
|
|
@@ -27,6 +42,8 @@ export {
|
|
|
27
42
|
graphContentHash,
|
|
28
43
|
renderAssetFileName,
|
|
29
44
|
renderAssetId,
|
|
45
|
+
walkthroughAssetFileName,
|
|
46
|
+
walkthroughAssetId,
|
|
30
47
|
type AssetAddress,
|
|
31
48
|
} from "./manifest.js";
|
|
32
49
|
|
package/src/manifest.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import type { GraphDoc, Lens, RenderAsset, RenderManifest } from "@coldtea/pr-lens-schema";
|
|
2
|
+
import type { GraphDoc, Lens, RenderAsset, RenderManifest, WalkthroughAsset } from "@coldtea/pr-lens-schema";
|
|
3
3
|
import { SCHEMA_VERSION } from "@coldtea/pr-lens-schema";
|
|
4
|
-
import { THEMES, type Theme } from "./theme.js";
|
|
4
|
+
import { THEMES, type PairTheme, type Theme } from "./theme.js";
|
|
5
5
|
import { RENDERER_NAME, RENDERER_VERSION } from "./version.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -23,6 +23,12 @@ export const CONTENT_HASH_LENGTH = 32;
|
|
|
23
23
|
export const contentHash = (bytes: string): string =>
|
|
24
24
|
createHash("sha256").update(bytes, "utf8").digest("hex").slice(0, CONTENT_HASH_LENGTH);
|
|
25
25
|
|
|
26
|
+
/** The one place an asset's bytes become its identity. */
|
|
27
|
+
export const assetIdentity = (svg: string): { contentHash: string; bytes: number } => ({
|
|
28
|
+
contentHash: contentHash(svg),
|
|
29
|
+
bytes: Buffer.byteLength(svg, "utf8"),
|
|
30
|
+
});
|
|
31
|
+
|
|
26
32
|
/** JSON with object keys in sorted order, so equal documents hash equal. */
|
|
27
33
|
export const canonicalJson = (value: unknown): string => {
|
|
28
34
|
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
|
|
@@ -106,7 +112,17 @@ export const renderAssetId = ({ lens, theme, view }: AssetAddress): string =>
|
|
|
106
112
|
export const renderAssetFileName = (address: AssetAddress, hash: string): string =>
|
|
107
113
|
`${renderAssetId(address)}-${hash}.svg`;
|
|
108
114
|
|
|
109
|
-
|
|
115
|
+
/** Listed apart from the view assets, so a view called "walkthrough" cannot collide with it. */
|
|
116
|
+
export const walkthroughAssetId = (theme: PairTheme): string => `walkthrough-${theme}`;
|
|
117
|
+
|
|
118
|
+
export const walkthroughAssetFileName = (theme: PairTheme, hash: string): string =>
|
|
119
|
+
`${walkthroughAssetId(theme)}-${hash}.svg`;
|
|
120
|
+
|
|
121
|
+
export const buildManifest = (
|
|
122
|
+
doc: GraphDoc,
|
|
123
|
+
assets: readonly RenderAsset[],
|
|
124
|
+
walkthrough: readonly WalkthroughAsset[],
|
|
125
|
+
): RenderManifest => ({
|
|
110
126
|
schemaVersion: SCHEMA_VERSION,
|
|
111
127
|
kind: "render-manifest",
|
|
112
128
|
graph: {
|
|
@@ -116,4 +132,5 @@ export const buildManifest = (doc: GraphDoc, assets: readonly RenderAsset[]): Re
|
|
|
116
132
|
},
|
|
117
133
|
renderer: { name: RENDERER_NAME, version: RENDERER_VERSION },
|
|
118
134
|
assets: [...assets],
|
|
135
|
+
walkthrough: [...walkthrough],
|
|
119
136
|
});
|