@webpieces/nx-webpieces-rules 0.4.911 → 0.4.913
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 +11 -0
- package/executors.json +5 -0
- package/package.json +7 -7
- package/src/executors/help/executor.js +2 -0
- package/src/executors/help/executor.js.map +1 -1
- package/src/executors/visualize-runtime/executor.d.ts +3 -1
- package/src/executors/visualize-runtime/executor.js +9 -3
- package/src/executors/visualize-runtime/executor.js.map +1 -1
- package/src/executors/visualize-runtime-goal/executor.d.ts +27 -0
- package/src/executors/visualize-runtime-goal/executor.js +98 -0
- package/src/executors/visualize-runtime-goal/executor.js.map +1 -0
- package/src/executors/visualize-runtime-goal/schema.json +13 -0
- package/src/index.d.ts +1 -1
- package/src/index.js +3 -1
- package/src/index.js.map +1 -1
- package/src/lib/graph-color-modes.d.ts +15 -1
- package/src/lib/graph-color-modes.js +19 -1
- package/src/lib/graph-color-modes.js.map +1 -1
- package/src/lib/graph-filter.client.d.ts +9 -2
- package/src/lib/graph-filter.client.js +15 -0
- package/src/lib/graph-filter.client.js.map +1 -1
- package/src/lib/graph-legend.js +1 -1
- package/src/lib/graph-legend.js.map +1 -1
- package/src/lib/graph-mode-state.client.d.ts +9 -2
- package/src/lib/graph-mode-state.client.js +17 -4
- package/src/lib/graph-mode-state.client.js.map +1 -1
- package/src/lib/graph-page-shell.d.ts +11 -4
- package/src/lib/graph-page-shell.js +11 -9
- package/src/lib/graph-page-shell.js.map +1 -1
- package/src/lib/graph-products.d.ts +22 -3
- package/src/lib/graph-products.js +63 -13
- package/src/lib/graph-products.js.map +1 -1
- package/src/lib/graph-render-model.d.ts +41 -0
- package/src/lib/graph-render-model.js +45 -1
- package/src/lib/graph-render-model.js.map +1 -1
- package/src/lib/graph-visualizer.client.d.ts +7 -1
- package/src/lib/graph-visualizer.client.js +37 -4
- package/src/lib/graph-visualizer.client.js.map +1 -1
- package/src/lib/graph-visualizer.js +1 -1
- package/src/lib/graph-visualizer.js.map +1 -1
- package/src/lib/runtime-goal-comparison.d.ts +55 -0
- package/src/lib/runtime-goal-comparison.js +209 -0
- package/src/lib/runtime-goal-comparison.js.map +1 -0
- package/src/lib/runtime-goal-details.d.ts +17 -0
- package/src/lib/runtime-goal-details.js +118 -0
- package/src/lib/runtime-goal-details.js.map +1 -0
- package/src/lib/runtime-goal-file.d.ts +72 -0
- package/src/lib/runtime-goal-file.js +201 -0
- package/src/lib/runtime-goal-file.js.map +1 -0
- package/src/lib/runtime-goal-styles.d.ts +10 -0
- package/src/lib/runtime-goal-styles.js +25 -0
- package/src/lib/runtime-goal-styles.js.map +1 -0
- package/src/lib/runtime-goal-validator.d.ts +39 -0
- package/src/lib/runtime-goal-validator.js +236 -0
- package/src/lib/runtime-goal-validator.js.map +1 -0
- package/src/lib/runtime-goal-view.d.ts +22 -0
- package/src/lib/runtime-goal-view.js +64 -0
- package/src/lib/runtime-goal-view.js.map +1 -0
- package/src/lib/runtime-graph-diff.d.ts +107 -0
- package/src/lib/runtime-graph-diff.js +346 -0
- package/src/lib/runtime-graph-diff.js.map +1 -0
- package/src/lib/runtime-html-page.d.ts +8 -0
- package/src/lib/runtime-html-page.js +39 -6
- package/src/lib/runtime-html-page.js.map +1 -1
- package/src/lib/runtime-layout.d.ts +2 -0
- package/src/lib/runtime-layout.js +4 -0
- package/src/lib/runtime-layout.js.map +1 -1
- package/src/lib/runtime-union-graph.d.ts +20 -0
- package/src/lib/runtime-union-graph.js +94 -0
- package/src/lib/runtime-union-graph.js.map +1 -0
- package/src/lib/runtime-viewer-adapter.js +7 -5
- package/src/lib/runtime-viewer-adapter.js.map +1 -1
- package/src/lib/runtime-visualizer.client.js +7 -3
- package/src/lib/runtime-visualizer.client.js.map +1 -1
- package/src/lib/runtime-visualizer.d.ts +8 -3
- package/src/lib/runtime-visualizer.js +18 -10
- package/src/lib/runtime-visualizer.js.map +1 -1
- package/src/lib/runtime-viz-options.d.ts +28 -1
- package/src/lib/runtime-viz-options.js +36 -2
- package/src/lib/runtime-viz-options.js.map +1 -1
- package/src/plugin.js +2 -2
- package/src/plugin.js.map +1 -1
- package/src/runtime-targets.d.ts +6 -0
- package/src/runtime-targets.js +17 -0
- package/src/runtime-targets.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-layout.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-layout.ts"],"names":[],"mappings":";;;AAAA,6DAAoE;AACpE,2DAAsD;AAEtD,yFAAyF;AACzF,MAAa,aAAa;IACtB,MAAM,CAAC,KAAuB;QAC1B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC7B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAS;gBAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACpE,CAAC;QACD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;YACtD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAChC,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAE,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAE;gBAAE,SAAS;YAC5D,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,+BAAU,CAC/B,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,EAC5B,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CACxE,CAAC;QACN,CAAC;QACD,OAAO,CACH,KAAK,CAAC,MAAM;YACZ,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5C,IAAI,mCAAe,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;YACtC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5C,KAAK,CAAC,MAAM,CACf,CAAC;IACN,CAAC;IAEO,aAAa,CAAC,GAAW;QAC7B,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,wBAAwB,CAAC;IACvD,CAAC;CACJ;
|
|
1
|
+
{"version":3,"file":"runtime-layout.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-layout.ts"],"names":[],"mappings":";;;AAAA,6DAAoE;AACpE,2DAAsD;AAEtD,yFAAyF;AACzF,MAAa,aAAa;IACtB,MAAM,CAAC,KAAuB;QAC1B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC7B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAS;gBAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACpE,CAAC;QACD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;YACtD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAChC,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAE,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAE;gBAAE,SAAS;YAC5D,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,+BAAU,CAC/B,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,EAC5B,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CACxE,CAAC;QACN,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED,uGAAuG;IACvG,QAAQ,CAAC,KAAuB;QAC5B,OAAO,CACH,KAAK,CAAC,MAAM;YACZ,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5C,IAAI,mCAAe,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;YACtC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5C,KAAK,CAAC,MAAM,CACf,CAAC;IACN,CAAC;IAEO,aAAa,CAAC,GAAW;QAC7B,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,wBAAwB,CAAC;IACvD,CAAC;CACJ;AAlCD,sCAkCC","sourcesContent":["import { GraphRenderModel, RenderEdge } from './graph-render-model';\nimport { LevelBandLayout } from './graph-level-bands';\n\n/** Saved levels own layout; real feedback arrows remain visible without moving ranks. */\nexport class RuntimeLayout {\n render(model: GraphRenderModel): string {\n const levels = new Map<string, number>();\n for (const band of model.bands) {\n for (const name of band.nodeNames) levels.set(name, band.level);\n }\n for (let index = 0; index < model.edges.length; index++) {\n const edge = model.edges[index];\n if (levels.get(edge.from)! > levels.get(edge.to)!) continue;\n model.edges[index] = new RenderEdge(\n edge.from,\n edge.to,\n this.unconstrained(edge.dot),\n edge.id,\n edge.productDot === null ? null : this.unconstrained(edge.productDot),\n );\n }\n return this.assemble(model);\n }\n\n /** The DOT for the model's current statements, without re-deciding constraints (restyled overlays). */\n assemble(model: GraphRenderModel): string {\n return (\n model.header +\n model.nodes.map((node) => node.dot).join('') +\n new LevelBandLayout().dot(model.bands) +\n model.edges.map((edge) => edge.dot).join('') +\n model.footer\n );\n }\n\n private unconstrained(dot: string): string {\n return `${dot.slice(0, -2)} [constraint=false];\\n`;\n }\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { RuntimeGraph } from './runtime-graph-model';
|
|
2
|
+
/**
|
|
3
|
+
* The OVERLAY drawn by Goal vs Current (#1239): every goal element, plus every element only the
|
|
4
|
+
* current graph has, so removals stay visible instead of silently disappearing.
|
|
5
|
+
*
|
|
6
|
+
* Presentation only. It is never levelled, never cycle-checked and never saved: an overlay of two
|
|
7
|
+
* architectures can contain a cycle neither input has, and that is not an architectural finding.
|
|
8
|
+
* Every element keeps the level its OWN graph saved — retained and added elements sit at their goal
|
|
9
|
+
* level, removed ones at their current level — so the shared renderer's strict level bands still
|
|
10
|
+
* order the rows and only real upward edges become non-constraining feedback edges.
|
|
11
|
+
*/
|
|
12
|
+
export declare class RuntimeUnionGraph {
|
|
13
|
+
build(current: RuntimeGraph, goal: RuntimeGraph): RuntimeGraph;
|
|
14
|
+
/** Edges matched on (transport, from, to, queue); a matched edge carries both graphs' contracts. */
|
|
15
|
+
private edges;
|
|
16
|
+
private missing;
|
|
17
|
+
private externals;
|
|
18
|
+
private remotes;
|
|
19
|
+
private copy;
|
|
20
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RuntimeUnionGraph = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The OVERLAY drawn by Goal vs Current (#1239): every goal element, plus every element only the
|
|
6
|
+
* current graph has, so removals stay visible instead of silently disappearing.
|
|
7
|
+
*
|
|
8
|
+
* Presentation only. It is never levelled, never cycle-checked and never saved: an overlay of two
|
|
9
|
+
* architectures can contain a cycle neither input has, and that is not an architectural finding.
|
|
10
|
+
* Every element keeps the level its OWN graph saved — retained and added elements sit at their goal
|
|
11
|
+
* level, removed ones at their current level — so the shared renderer's strict level bands still
|
|
12
|
+
* order the rows and only real upward edges become non-constraining feedback edges.
|
|
13
|
+
*/
|
|
14
|
+
class RuntimeUnionGraph {
|
|
15
|
+
build(current, goal) {
|
|
16
|
+
const union = this.copy(goal);
|
|
17
|
+
const old = this.copy(current);
|
|
18
|
+
for (const [name, service] of Object.entries(old.services))
|
|
19
|
+
union.services[name] ??= service;
|
|
20
|
+
for (const [name, api] of Object.entries(old.apis))
|
|
21
|
+
union.apis[name] ??= api;
|
|
22
|
+
for (const [key, queue] of Object.entries(old.queues))
|
|
23
|
+
union.queues[key] ??= queue;
|
|
24
|
+
for (const [api, queue] of Object.entries(old.contractQueues))
|
|
25
|
+
union.contractQueues[api] ??= queue;
|
|
26
|
+
union.runtimeEdges = this.edges(union.runtimeEdges, old.runtimeEdges);
|
|
27
|
+
union.triggers = this.missing(union.triggers, old.triggers, (trigger) => `${trigger.kind} ${trigger.api}.${trigger.method} ${trigger.service}`);
|
|
28
|
+
union.unresolvedUses = this.missing(union.unresolvedUses, old.unresolvedUses, (use) => `${use.service} ${use.api}`);
|
|
29
|
+
this.externals(union, old);
|
|
30
|
+
this.remotes(union, old);
|
|
31
|
+
union.maxLevel = Math.max(union.maxLevel, old.maxLevel);
|
|
32
|
+
return union;
|
|
33
|
+
}
|
|
34
|
+
/** Edges matched on (transport, from, to, queue); a matched edge carries both graphs' contracts. */
|
|
35
|
+
edges(goal, current) {
|
|
36
|
+
const key = (edge) => `${edge.type ?? 'rpc'} ${edge.from} ${edge.to} ${edge.queue ?? ''}`;
|
|
37
|
+
const byKey = new Map();
|
|
38
|
+
for (const edge of goal)
|
|
39
|
+
byKey.set(key(edge), edge);
|
|
40
|
+
const out = [...goal];
|
|
41
|
+
for (const edge of current) {
|
|
42
|
+
const match = byKey.get(key(edge));
|
|
43
|
+
if (match === undefined) {
|
|
44
|
+
byKey.set(key(edge), edge);
|
|
45
|
+
out.push(edge);
|
|
46
|
+
}
|
|
47
|
+
else
|
|
48
|
+
match.via = [...new Set([...match.via, ...edge.via])].sort();
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
missing(goal, current, key) {
|
|
53
|
+
const seen = new Set(goal.map(key));
|
|
54
|
+
return [...goal, ...current.filter((value) => !seen.has(key(value)))];
|
|
55
|
+
}
|
|
56
|
+
externals(union, old) {
|
|
57
|
+
if (union.externalSystems === undefined && old.externalSystems === undefined)
|
|
58
|
+
return;
|
|
59
|
+
const systems = (union.externalSystems ??= {});
|
|
60
|
+
for (const [id, system] of Object.entries(old.externalSystems ?? {})) {
|
|
61
|
+
const kept = systems[id];
|
|
62
|
+
if (kept === undefined) {
|
|
63
|
+
systems[id] = system;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
kept.usedBy = [...new Set([...kept.usedBy, ...system.usedBy])].sort();
|
|
67
|
+
kept.apis = [...new Set([...kept.apis, ...system.apis])].sort();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
remotes(union, old) {
|
|
71
|
+
if (union.remoteServices === undefined && old.remoteServices === undefined)
|
|
72
|
+
return;
|
|
73
|
+
const remotes = (union.remoteServices ??= {});
|
|
74
|
+
for (const [name, remote] of Object.entries(old.remoteServices ?? {})) {
|
|
75
|
+
const kept = remotes[name];
|
|
76
|
+
if (kept === undefined) {
|
|
77
|
+
remotes[name] = remote;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
for (const call of remote.calledBy) {
|
|
81
|
+
const match = kept.calledBy.find((entry) => entry.from === call.from && entry.type === call.type);
|
|
82
|
+
if (match === undefined)
|
|
83
|
+
kept.calledBy.push(call);
|
|
84
|
+
else
|
|
85
|
+
match.via = [...new Set([...match.via, ...call.via])].sort();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
copy(graph) {
|
|
90
|
+
return JSON.parse(JSON.stringify(graph));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.RuntimeUnionGraph = RuntimeUnionGraph;
|
|
94
|
+
//# sourceMappingURL=runtime-union-graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-union-graph.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-union-graph.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RuntimeEdge,\n RuntimeGraph,\n RuntimeRemoteCall,\n RuntimeTrigger,\n RuntimeUnresolved,\n} from './runtime-graph-model';\n\n/**\n * The OVERLAY drawn by Goal vs Current (#1239): every goal element, plus every element only the\n * current graph has, so removals stay visible instead of silently disappearing.\n *\n * Presentation only. It is never levelled, never cycle-checked and never saved: an overlay of two\n * architectures can contain a cycle neither input has, and that is not an architectural finding.\n * Every element keeps the level its OWN graph saved — retained and added elements sit at their goal\n * level, removed ones at their current level — so the shared renderer's strict level bands still\n * order the rows and only real upward edges become non-constraining feedback edges.\n */\nexport class RuntimeUnionGraph {\n build(current: RuntimeGraph, goal: RuntimeGraph): RuntimeGraph {\n const union = this.copy(goal);\n const old = this.copy(current);\n for (const [name, service] of Object.entries(old.services)) union.services[name] ??= service;\n for (const [name, api] of Object.entries(old.apis)) union.apis[name] ??= api;\n for (const [key, queue] of Object.entries(old.queues)) union.queues[key] ??= queue;\n for (const [api, queue] of Object.entries(old.contractQueues)) union.contractQueues[api] ??= queue;\n union.runtimeEdges = this.edges(union.runtimeEdges, old.runtimeEdges);\n union.triggers = this.missing(union.triggers, old.triggers, (trigger: RuntimeTrigger) => `${trigger.kind} ${trigger.api}.${trigger.method} ${trigger.service}`);\n union.unresolvedUses = this.missing(union.unresolvedUses, old.unresolvedUses, (use: RuntimeUnresolved) => `${use.service} ${use.api}`);\n this.externals(union, old);\n this.remotes(union, old);\n union.maxLevel = Math.max(union.maxLevel, old.maxLevel);\n return union;\n }\n\n /** Edges matched on (transport, from, to, queue); a matched edge carries both graphs' contracts. */\n private edges(goal: RuntimeEdge[], current: RuntimeEdge[]): RuntimeEdge[] {\n const key = (edge: RuntimeEdge): string => `${edge.type ?? 'rpc'} ${edge.from} ${edge.to} ${edge.queue ?? ''}`;\n const byKey = new Map<string, RuntimeEdge>();\n for (const edge of goal) byKey.set(key(edge), edge);\n const out = [...goal];\n for (const edge of current) {\n const match = byKey.get(key(edge));\n if (match === undefined) {\n byKey.set(key(edge), edge);\n out.push(edge);\n } else match.via = [...new Set([...match.via, ...edge.via])].sort();\n }\n return out;\n }\n\n private missing<T>(goal: T[], current: T[], key: (value: T) => string): T[] {\n const seen = new Set(goal.map(key));\n return [...goal, ...current.filter((value: T) => !seen.has(key(value)))];\n }\n\n private externals(union: RuntimeGraph, old: RuntimeGraph): void {\n if (union.externalSystems === undefined && old.externalSystems === undefined) return;\n const systems = (union.externalSystems ??= {});\n for (const [id, system] of Object.entries(old.externalSystems ?? {})) {\n const kept = systems[id];\n if (kept === undefined) {\n systems[id] = system;\n continue;\n }\n kept.usedBy = [...new Set([...kept.usedBy, ...system.usedBy])].sort();\n kept.apis = [...new Set([...kept.apis, ...system.apis])].sort();\n }\n }\n\n private remotes(union: RuntimeGraph, old: RuntimeGraph): void {\n if (union.remoteServices === undefined && old.remoteServices === undefined) return;\n const remotes = (union.remoteServices ??= {});\n for (const [name, remote] of Object.entries(old.remoteServices ?? {})) {\n const kept = remotes[name];\n if (kept === undefined) {\n remotes[name] = remote;\n continue;\n }\n for (const call of remote.calledBy) {\n const match = kept.calledBy.find((entry: RuntimeRemoteCall) => entry.from === call.from && entry.type === call.type);\n if (match === undefined) kept.calledBy.push(call);\n else match.via = [...new Set([...match.via, ...call.via])].sort();\n }\n }\n }\n\n private copy(graph: RuntimeGraph): RuntimeGraph {\n return JSON.parse(JSON.stringify(graph)) as RuntimeGraph;\n }\n}\n"]}
|
|
@@ -16,11 +16,13 @@ class RuntimeViewerAdapter {
|
|
|
16
16
|
constructor(graph, projects) {
|
|
17
17
|
this.graph = graph;
|
|
18
18
|
this.projects = projects;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
// The FULL declared product set (#1244), never just the services drawn here: collision
|
|
20
|
+
// resolution depends on the set, so a subset could recolor a product away from the color the
|
|
21
|
+
// dependency viewer gives it.
|
|
22
|
+
const declared = Object.values(graph.services).flatMap((service) => service.products ?? []);
|
|
23
|
+
if (projects !== null)
|
|
24
|
+
declared.push(...graph_products_1.ProductPalette.fromGraph(projects).names());
|
|
25
|
+
this.palette = new graph_products_1.ProductPalette(declared);
|
|
24
26
|
}
|
|
25
27
|
service(model, name, service) {
|
|
26
28
|
const project = this.projects?.[name];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-viewer-adapter.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-viewer-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EnhancedGraph } from './graph-sorter';\nimport type { RuntimeGraph, RuntimeService } from './runtime-graph-model';\nimport { GraphRenderModel, RenderNode } from './graph-render-model';\nimport { NodeFacts, NodeModeDots, NodeModeStyler } from './graph-color-modes';\nimport { ProductPalette, PRODUCT_SHARED_FILL, PRODUCT_NONE_FILL } from './graph-products';\nimport { LevelBand } from './graph-level-bands';\nimport { RemoteServiceNodeId } from './remote-service-node-id';\nimport { RuntimeExternalTriggers } from './runtime-external-triggers';\n\n/** Saved project facts enrich presentation without changing runtime derivation or topology. */\nexport class RuntimeViewerAdapter {\n private readonly styler = new NodeModeStyler();\n private readonly palette: ProductPalette;\n\n constructor(\n private readonly graph: RuntimeGraph,\n private readonly projects: EnhancedGraph | null,\n ) {\n this.palette = new ProductPalette(\n [\n ...new Set(\n Object.values(graph.services)\n .filter((service) => service.drawOnGraph !== false)\n .flatMap((service) => service.products ?? []),\n ),\n ].sort(),\n );\n }\n\n service(model: GraphRenderModel, name: string, service: RuntimeService): string {\n const project = this.projects?.[name];\n const role = service.role ?? project?.role ?? 'unknown';\n const facts = new NodeFacts(\n name,\n name.split('/').pop() ?? name,\n service.level,\n role,\n project?.framework ?? [],\n service.products ?? [],\n `Implements (${new Set(service.implements).size})${service.serviceName === undefined ? '' : ` · \"${service.serviceName}\"`}`,\n );\n this.styler.record(model.legend, facts, this.palette);\n return model.styledNode(facts, this.styler.dots(facts, this.palette));\n }\n\n levelBands(model: GraphRenderModel): LevelBand[] {\n const levels = new Map<string, number>();\n const selfQueues = new Set<string>();\n const safe = (name: string): string => name.replace(/[^A-Za-z0-9_]/g, '_');\n for (const [name, service] of Object.entries(this.graph.services))\n levels.set(name, service.level);\n for (const node of model.nodes) {\n if (node.queueKeys.length === 0) continue;\n const key = node.queueKeys[0];\n const queue = key.startsWith('queue:')\n ? this.graph.contractQueues[key.slice(6)]\n : this.graph.queues[key];\n levels.set(node.id, queue.level);\n if (queue.selfQueue && queue.producedBy.length > 0) selfQueues.add(node.id);\n }\n for (const [name, system] of Object.entries(this.graph.externalSystems ?? {}))\n levels.set(`system__${safe(name)}`, system.level);\n for (const [name, remote] of Object.entries(this.graph.remoteServices ?? {}))\n levels.set(new RemoteServiceNodeId().of(name), remote.level);\n for (const trigger of this.graph.triggers) {\n if (trigger.kind === 'cron')\n levels.set(`cron__${safe(`${trigger.api}_${trigger.method}`)}`, trigger.level);\n }\n for (const group of new RuntimeExternalTriggers(this.graph.triggers).groups)\n levels.set(group.from, group.triggers[0].level);\n // Undeclared vendor seams are terminal sinks too, independent of their grouping for display.\n for (const use of this.graph.unresolvedUses) {\n const owner = this.graph.apis[use.api]?.owner ?? use.api;\n levels.set(`external__${owner}`, use.level);\n }\n const bands = new Map<number, string[]>();\n for (const node of model.nodes) {\n const level = levels.get(node.id)!;\n if (!bands.has(level)) bands.set(level, []);\n bands.get(level)!.push(node.id);\n }\n return [...bands.entries()]\n .sort((a, b) => b[0] - a[0])\n .map((entry) => {\n const band = new LevelBand(entry[0], entry[1]);\n band.selfQueueNames = entry[1].filter((id) => selfQueues.has(id));\n return band;\n });\n }\n\n /** Context keeps its shape/kind palette; Impact never paints a queue as a source owner. */\n contextModes(model: GraphRenderModel): void {\n for (let index = 0; index < model.nodes.length; index++) {\n const node = model.nodes[index];\n if (node.tags !== null) continue;\n const colors = node.products.map((product) => this.palette.colorOf(product).color);\n const fill =\n colors.length === 0\n ? PRODUCT_NONE_FILL\n : this.palette.sharedByAll(node.products)\n ? PRODUCT_SHARED_FILL\n : colors.join(':');\n // Graphviz cylinders cannot stripe; a gradient preserves recognizable kind geometry.\n const recolored = node.dot.replace(/fillcolor=\"[^\"]*\"/, `fillcolor=\"${fill}\"`);\n const product =\n colors.length === 0\n ? recolored.replace(/style=\"[^\"]*\"/, 'style=\"filled,dashed\"')\n : recolored;\n const modes = new NodeModeDots(\n node.dot,\n node.dot,\n node.dot,\n node.dot,\n node.dot,\n node.dot,\n product,\n );\n model.nodes[index] = new RenderNode(\n node.id,\n node.dot,\n modes,\n null,\n node.products,\n node.queueKeys,\n );\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"runtime-viewer-adapter.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-viewer-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EnhancedGraph } from './graph-sorter';\nimport type { RuntimeGraph, RuntimeService } from './runtime-graph-model';\nimport { GraphRenderModel, RenderNode } from './graph-render-model';\nimport { NodeFacts, NodeModeDots, NodeModeStyler } from './graph-color-modes';\nimport { ProductPalette, PRODUCT_SHARED_FILL, PRODUCT_NONE_FILL } from './graph-products';\nimport { LevelBand } from './graph-level-bands';\nimport { RemoteServiceNodeId } from './remote-service-node-id';\nimport { RuntimeExternalTriggers } from './runtime-external-triggers';\n\n/** Saved project facts enrich presentation without changing runtime derivation or topology. */\nexport class RuntimeViewerAdapter {\n private readonly styler = new NodeModeStyler();\n private readonly palette: ProductPalette;\n\n constructor(\n private readonly graph: RuntimeGraph,\n private readonly projects: EnhancedGraph | null,\n ) {\n // The FULL declared product set (#1244), never just the services drawn here: collision\n // resolution depends on the set, so a subset could recolor a product away from the color the\n // dependency viewer gives it.\n const declared = Object.values(graph.services).flatMap((service) => service.products ?? []);\n if (projects !== null) declared.push(...ProductPalette.fromGraph(projects).names());\n this.palette = new ProductPalette(declared);\n }\n\n service(model: GraphRenderModel, name: string, service: RuntimeService): string {\n const project = this.projects?.[name];\n const role = service.role ?? project?.role ?? 'unknown';\n const facts = new NodeFacts(\n name,\n name.split('/').pop() ?? name,\n service.level,\n role,\n project?.framework ?? [],\n service.products ?? [],\n `Implements (${new Set(service.implements).size})${service.serviceName === undefined ? '' : ` · \"${service.serviceName}\"`}`,\n );\n this.styler.record(model.legend, facts, this.palette);\n return model.styledNode(facts, this.styler.dots(facts, this.palette));\n }\n\n levelBands(model: GraphRenderModel): LevelBand[] {\n const levels = new Map<string, number>();\n const selfQueues = new Set<string>();\n const safe = (name: string): string => name.replace(/[^A-Za-z0-9_]/g, '_');\n for (const [name, service] of Object.entries(this.graph.services))\n levels.set(name, service.level);\n for (const node of model.nodes) {\n if (node.queueKeys.length === 0) continue;\n const key = node.queueKeys[0];\n const queue = key.startsWith('queue:')\n ? this.graph.contractQueues[key.slice(6)]\n : this.graph.queues[key];\n levels.set(node.id, queue.level);\n if (queue.selfQueue && queue.producedBy.length > 0) selfQueues.add(node.id);\n }\n for (const [name, system] of Object.entries(this.graph.externalSystems ?? {}))\n levels.set(`system__${safe(name)}`, system.level);\n for (const [name, remote] of Object.entries(this.graph.remoteServices ?? {}))\n levels.set(new RemoteServiceNodeId().of(name), remote.level);\n for (const trigger of this.graph.triggers) {\n if (trigger.kind === 'cron')\n levels.set(`cron__${safe(`${trigger.api}_${trigger.method}`)}`, trigger.level);\n }\n for (const group of new RuntimeExternalTriggers(this.graph.triggers).groups)\n levels.set(group.from, group.triggers[0].level);\n // Undeclared vendor seams are terminal sinks too, independent of their grouping for display.\n for (const use of this.graph.unresolvedUses) {\n const owner = this.graph.apis[use.api]?.owner ?? use.api;\n levels.set(`external__${owner}`, use.level);\n }\n const bands = new Map<number, string[]>();\n for (const node of model.nodes) {\n const level = levels.get(node.id)!;\n if (!bands.has(level)) bands.set(level, []);\n bands.get(level)!.push(node.id);\n }\n return [...bands.entries()]\n .sort((a, b) => b[0] - a[0])\n .map((entry) => {\n const band = new LevelBand(entry[0], entry[1]);\n band.selfQueueNames = entry[1].filter((id) => selfQueues.has(id));\n return band;\n });\n }\n\n /** Context keeps its shape/kind palette; Impact never paints a queue as a source owner. */\n contextModes(model: GraphRenderModel): void {\n for (let index = 0; index < model.nodes.length; index++) {\n const node = model.nodes[index];\n if (node.tags !== null) continue;\n const colors = node.products.map((product) => this.palette.colorOf(product).color);\n const fill =\n colors.length === 0\n ? PRODUCT_NONE_FILL\n : this.palette.sharedByAll(node.products)\n ? PRODUCT_SHARED_FILL\n : colors.join(':');\n // Graphviz cylinders cannot stripe; a gradient preserves recognizable kind geometry.\n const recolored = node.dot.replace(/fillcolor=\"[^\"]*\"/, `fillcolor=\"${fill}\"`);\n const product =\n colors.length === 0\n ? recolored.replace(/style=\"[^\"]*\"/, 'style=\"filled,dashed\"')\n : recolored;\n const modes = new NodeModeDots(\n node.dot,\n node.dot,\n node.dot,\n node.dot,\n node.dot,\n node.dot,\n product,\n );\n model.nodes[index] = new RenderNode(\n node.id,\n node.dot,\n modes,\n null,\n node.products,\n node.queueKeys,\n );\n }\n }\n}\n"]}
|
|
@@ -82,6 +82,8 @@ class QueueCylinders {
|
|
|
82
82
|
const first = shapes[0];
|
|
83
83
|
const fill = first.getAttribute('fill') ?? 'none';
|
|
84
84
|
const stroke = first.getAttribute('stroke') ?? 'black';
|
|
85
|
+
// A dashed outline (Goal vs Current's removed queue, #1239) survives the redraw.
|
|
86
|
+
const dash = first.getAttribute('stroke-dasharray');
|
|
85
87
|
// Measured BEFORE the shapes go: the record separator is where the label text starts.
|
|
86
88
|
const separator = this.separatorX(shapes);
|
|
87
89
|
shapes.forEach((shape) => {
|
|
@@ -107,8 +109,8 @@ class QueueCylinders {
|
|
|
107
109
|
const anchor = node.firstChild;
|
|
108
110
|
if (anchor === null || anchor.nextSibling === null)
|
|
109
111
|
return;
|
|
110
|
-
node.insertBefore(this.pathEl(fill, stroke, body), anchor.nextSibling);
|
|
111
|
-
node.insertBefore(this.pathEl('none', stroke, cap), anchor.nextSibling.nextSibling);
|
|
112
|
+
node.insertBefore(this.pathEl(fill, stroke, body, dash), anchor.nextSibling);
|
|
113
|
+
node.insertBefore(this.pathEl('none', stroke, cap, dash), anchor.nextSibling.nextSibling);
|
|
112
114
|
// The label is deliberately NOT nudged. QUEUE_LABEL_PREFIX already gives the node an empty
|
|
113
115
|
// leading record field, so Graphviz has centred the text in the space to the RIGHT of where the
|
|
114
116
|
// cap lands. Shifting it again double-counts that offset and pushes the longest line out
|
|
@@ -193,10 +195,12 @@ class QueueCylinders {
|
|
|
193
195
|
return null;
|
|
194
196
|
return new Bounds(Math.min(...xs), Math.max(...xs), Math.min(...ys), Math.max(...ys));
|
|
195
197
|
}
|
|
196
|
-
pathEl(fill, stroke, d) {
|
|
198
|
+
pathEl(fill, stroke, d, dash) {
|
|
197
199
|
const el = document.createElementNS(QueueCylinders.SVG_NS, 'path');
|
|
198
200
|
el.setAttribute('fill', fill);
|
|
199
201
|
el.setAttribute('stroke', stroke);
|
|
202
|
+
if (dash !== null)
|
|
203
|
+
el.setAttribute('stroke-dasharray', dash);
|
|
200
204
|
el.setAttribute('d', d);
|
|
201
205
|
return el;
|
|
202
206
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-visualizer.client.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-visualizer.client.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Browser-side script for tmp/webpieces/runtime-architecture.html.\n *\n * runtime-visualizer.ts reads this file's COMPILED output with readFileSync, substitutes the DOT\n * placeholder (see viz-client-globals.d.ts) with the JSON-encoded DOT, and inlines the result into a <script> tag. It runs in a\n * browser, never in node — but it is ordinary TypeScript, compiled in place by tsc like the package's\n * bin entry points, and linted like every other file here. (It used to be a committed .js asset\n * exempted from `no-js-files`; see graph-visualizer.client.ts for why that exemption is gone.)\n *\n * Three jobs:\n * 1. render the DOT with @viz-js/viz v3 (instance() resolves the WASM renderer, and\n * renderSVGElement is then SYNCHRONOUS — v2's returned a promise);\n * 2. upgrade every queue node into a TRUE horizontal cylinder;\n * 3. make every node clickable, opening the SHARED floating menu (graph-node-menu.ts — the same one\n * architecture/dependencies.html and every design.html use) with independent Lock/Unlock and chain filtering.\n *\n * Why (2) is post-processing rather than a shape:\n *\n * Graphviz has exactly one `cylinder` and it is upright-only. `orientation=` is documented as rotating\n * POLYGON shapes, and `cylinder` is drawn with beziers, so it silently ignores the attribute — graphviz\n * issue #2244, open since 2022 and still reproducible on Graphviz 15, the version this page's renderer\n * carries. All 54 native shapes were compared at the real label size; none is a horizontal cylinder. So\n * the DOT emits `Mrecord` (which renders sensibly on its own for anyone running `dot` over the\n * committed .dot file) and this script redraws it in the browser, where the geometry is computed from\n * each node's actual bounding box and therefore fits any label width — which a fixed image asset never\n * can.\n */\n\n// The DOT placeholder and the `Viz` global are declared once in viz-client-globals.d.ts — both\n// scripts share a global scope, so they cannot each declare them. Do NOT spell the placeholder token\n// in a comment: the inliner is a blind split/join, so every literal occurrence gets the whole DOT.\n\n/** Cap width as a fraction of the node's half-height. Below ~0.6 it reads as a rounded box. */\nconst CAP_RATIO = 0.75;\n/** A node narrower than this is not a queue box worth reshaping. */\nconst MIN_WIDTH = 40;\n\n/** The union bounding box of a node's shape elements, in user space. Data-only → a class. */\nclass Bounds {\n constructor(\n readonly x0: number,\n readonly x1: number,\n readonly y0: number,\n readonly y1: number,\n ) {}\n\n width(): number {\n return this.x1 - this.x0;\n }\n\n halfHeight(): number {\n return (this.y1 - this.y0) / 2;\n }\n}\n\n/**\n * Redraws the nodes the DOT marked `wp_queue` as cylinders lying on their side.\n *\n * Selected by CLASS, not by id prefix: a queue-kind external system shares the `system__` id space with\n * databases, and a database is an UPRIGHT cylinder that must be left alone.\n */\nclass QueueCylinders {\n private static readonly SVG_NS = 'http://www.w3.org/2000/svg';\n\n applyTo(svg: SVGSVGElement): void {\n svg.querySelectorAll('g.wp_queue').forEach((node: Element): void => {\n this.reshape(node);\n });\n }\n\n /**\n * Replace one node's shape elements with a horizontal cylinder sized to its own bounding box.\n *\n * The bbox is measured from the shape elements BEFORE they are removed, never from getBBox() on the\n * whole group — the group includes the text, which is inset, so using it would shrink the cylinder\n * inside the very label it is meant to contain.\n */\n private reshape(node: Element): void {\n const shapes = node.querySelectorAll('polygon, path, polyline');\n if (shapes.length === 0) return;\n const box = this.boundsOf(shapes);\n if (box === null || box.width() < MIN_WIDTH) return;\n\n const first = shapes[0];\n const fill = first.getAttribute('fill') ?? 'none';\n const stroke = first.getAttribute('stroke') ?? 'black';\n // Measured BEFORE the shapes go: the record separator is where the label text starts.\n const separator = this.separatorX(shapes);\n shapes.forEach((shape: Element): void => {\n shape.remove();\n });\n\n const ry = box.halfHeight();\n const rx = this.capRadius(box, ry, separator);\n const body = this.bodyPath(box, rx, ry);\n // Only the NEAR end cap is drawn: that single arc is what reads as \"tube\" rather than\n // \"stadium\", and a real cylinder hides the far one behind the body.\n const cap =\n 'M' +\n (box.x0 + rx) +\n ',' +\n box.y0 +\n ' A' +\n rx +\n ',' +\n ry +\n ' 0 0 1 ' +\n (box.x0 + rx) +\n ',' +\n box.y1;\n\n const anchor = node.firstChild;\n if (anchor === null || anchor.nextSibling === null) return;\n node.insertBefore(this.pathEl(fill, stroke, body), anchor.nextSibling);\n node.insertBefore(this.pathEl('none', stroke, cap), anchor.nextSibling.nextSibling);\n\n // The label is deliberately NOT nudged. QUEUE_LABEL_PREFIX already gives the node an empty\n // leading record field, so Graphviz has centred the text in the space to the RIGHT of where the\n // cap lands. Shifting it again double-counts that offset and pushes the longest line out\n // through the far end of the cylinder.\n }\n\n private bodyPath(box: Bounds, rx: number, ry: number): string {\n return (\n 'M' +\n (box.x0 + rx) +\n ',' +\n box.y0 +\n ' L' +\n (box.x1 - rx) +\n ',' +\n box.y0 +\n ' A' +\n rx +\n ',' +\n ry +\n ' 0 0 1 ' +\n (box.x1 - rx) +\n ',' +\n box.y1 +\n ' L' +\n (box.x0 + rx) +\n ',' +\n box.y1 +\n ' A' +\n rx +\n ',' +\n ry +\n ' 0 0 1 ' +\n (box.x0 + rx) +\n ',' +\n box.y0 +\n ' Z'\n );\n }\n\n /**\n * A box listing several queues is TALL, and a cap scaled off half-height alone would then reach\n * past the empty leading field and sit on top of the first characters of the label. Graphviz sizes\n * that field from the font, not from the label's height, so the separator is the only honest bound\n * on how far right the cap may go.\n */\n private capRadius(box: Bounds, ry: number, separator: number | null): number {\n const fromHeight = Math.max(6, ry * CAP_RATIO);\n if (separator === null) return fromHeight;\n return Math.max(6, Math.min(fromHeight, separator - box.x0));\n }\n\n /**\n * The x of the record's field separator — the VERTICAL polyline Graphviz draws between the empty\n * leading field and the label — or null if this node has none.\n */\n private separatorX(shapes: NodeListOf<Element>): number | null {\n for (const shape of Array.from(shapes)) {\n if (shape.tagName !== 'polyline') continue;\n const nums = (shape.getAttribute('points') ?? '').match(/-?[\\d.]+/g);\n if (nums === null || nums.length < 4) continue;\n const x = parseFloat(nums[0]);\n if (Math.abs(x - parseFloat(nums[2])) < 0.5) return x;\n }\n return null;\n }\n\n /** The union bounding box of some SVG shape elements, from their raw geometry attributes. */\n private boundsOf(shapes: NodeListOf<Element>): Bounds | null {\n const xs: number[] = [];\n const ys: number[] = [];\n for (const shape of Array.from(shapes)) {\n const pts = shape.getAttribute('points');\n const source = pts ?? shape.getAttribute('d') ?? '';\n const nums = source.match(/-?[\\d.]+/g);\n if (nums === null) continue;\n for (let n = 0; n + 1 < nums.length; n += 2) {\n xs.push(parseFloat(nums[n]));\n ys.push(parseFloat(nums[n + 1]));\n }\n }\n if (xs.length === 0) return null;\n return new Bounds(Math.min(...xs), Math.max(...xs), Math.min(...ys), Math.max(...ys));\n }\n\n private pathEl(fill: string, stroke: string, d: string): SVGPathElement {\n const el = document.createElementNS(QueueCylinders.SVG_NS, 'path');\n el.setAttribute('fill', fill);\n el.setAttribute('stroke', stroke);\n el.setAttribute('d', d);\n return el;\n }\n}\n\n/** Shape adapter for the shared viewer controller; no separate runtime control state. */\nclass RuntimeImplementsPayload {\n constructor(\n readonly name: string,\n readonly node: SVGGElement,\n ) {}\n}\n\nclass RuntimeViewerBindingImpl implements RuntimeViewerBinding {\n prepare(svg: SVGSVGElement): void {\n new QueueCylinders().applyTo(svg);\n // Keep identity titles readable by shared controllers without native SVG tooltips.\n svg.querySelectorAll('g.node > title, g.edge > title').forEach((title) => {\n title.parentElement?.setAttribute('aria-label', title.textContent ?? '');\n const identity = document.createElement('title');\n identity.textContent = title.textContent;\n title.replaceWith(identity);\n });\n }\n implementsItem(name: string, node: SVGGElement): WpNodeMenuItem | null {\n if (\n !node.querySelector('text') ||\n !Array.from(node.querySelectorAll('text')).some((text) =>\n text.textContent?.startsWith('Implements ('),\n )\n )\n return null;\n return new WpNodeMenuItem('Implements', (): void => {\n document.dispatchEvent(\n new CustomEvent('wp-runtime-implements', {\n detail: new RuntimeImplementsPayload(name, node),\n }),\n );\n });\n }\n}\nwindow.__WP_RUNTIME__ = new RuntimeViewerBindingImpl();\n"]}
|
|
1
|
+
{"version":3,"file":"runtime-visualizer.client.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-visualizer.client.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Browser-side script for tmp/webpieces/runtime-architecture.html.\n *\n * runtime-visualizer.ts reads this file's COMPILED output with readFileSync, substitutes the DOT\n * placeholder (see viz-client-globals.d.ts) with the JSON-encoded DOT, and inlines the result into a <script> tag. It runs in a\n * browser, never in node — but it is ordinary TypeScript, compiled in place by tsc like the package's\n * bin entry points, and linted like every other file here. (It used to be a committed .js asset\n * exempted from `no-js-files`; see graph-visualizer.client.ts for why that exemption is gone.)\n *\n * Three jobs:\n * 1. render the DOT with @viz-js/viz v3 (instance() resolves the WASM renderer, and\n * renderSVGElement is then SYNCHRONOUS — v2's returned a promise);\n * 2. upgrade every queue node into a TRUE horizontal cylinder;\n * 3. make every node clickable, opening the SHARED floating menu (graph-node-menu.ts — the same one\n * architecture/dependencies.html and every design.html use) with independent Lock/Unlock and chain filtering.\n *\n * Why (2) is post-processing rather than a shape:\n *\n * Graphviz has exactly one `cylinder` and it is upright-only. `orientation=` is documented as rotating\n * POLYGON shapes, and `cylinder` is drawn with beziers, so it silently ignores the attribute — graphviz\n * issue #2244, open since 2022 and still reproducible on Graphviz 15, the version this page's renderer\n * carries. All 54 native shapes were compared at the real label size; none is a horizontal cylinder. So\n * the DOT emits `Mrecord` (which renders sensibly on its own for anyone running `dot` over the\n * committed .dot file) and this script redraws it in the browser, where the geometry is computed from\n * each node's actual bounding box and therefore fits any label width — which a fixed image asset never\n * can.\n */\n\n// The DOT placeholder and the `Viz` global are declared once in viz-client-globals.d.ts — both\n// scripts share a global scope, so they cannot each declare them. Do NOT spell the placeholder token\n// in a comment: the inliner is a blind split/join, so every literal occurrence gets the whole DOT.\n\n/** Cap width as a fraction of the node's half-height. Below ~0.6 it reads as a rounded box. */\nconst CAP_RATIO = 0.75;\n/** A node narrower than this is not a queue box worth reshaping. */\nconst MIN_WIDTH = 40;\n\n/** The union bounding box of a node's shape elements, in user space. Data-only → a class. */\nclass Bounds {\n constructor(\n readonly x0: number,\n readonly x1: number,\n readonly y0: number,\n readonly y1: number,\n ) {}\n\n width(): number {\n return this.x1 - this.x0;\n }\n\n halfHeight(): number {\n return (this.y1 - this.y0) / 2;\n }\n}\n\n/**\n * Redraws the nodes the DOT marked `wp_queue` as cylinders lying on their side.\n *\n * Selected by CLASS, not by id prefix: a queue-kind external system shares the `system__` id space with\n * databases, and a database is an UPRIGHT cylinder that must be left alone.\n */\nclass QueueCylinders {\n private static readonly SVG_NS = 'http://www.w3.org/2000/svg';\n\n applyTo(svg: SVGSVGElement): void {\n svg.querySelectorAll('g.wp_queue').forEach((node: Element): void => {\n this.reshape(node);\n });\n }\n\n /**\n * Replace one node's shape elements with a horizontal cylinder sized to its own bounding box.\n *\n * The bbox is measured from the shape elements BEFORE they are removed, never from getBBox() on the\n * whole group — the group includes the text, which is inset, so using it would shrink the cylinder\n * inside the very label it is meant to contain.\n */\n private reshape(node: Element): void {\n const shapes = node.querySelectorAll('polygon, path, polyline');\n if (shapes.length === 0) return;\n const box = this.boundsOf(shapes);\n if (box === null || box.width() < MIN_WIDTH) return;\n\n const first = shapes[0];\n const fill = first.getAttribute('fill') ?? 'none';\n const stroke = first.getAttribute('stroke') ?? 'black';\n // A dashed outline (Goal vs Current's removed queue, #1239) survives the redraw.\n const dash = first.getAttribute('stroke-dasharray');\n // Measured BEFORE the shapes go: the record separator is where the label text starts.\n const separator = this.separatorX(shapes);\n shapes.forEach((shape: Element): void => {\n shape.remove();\n });\n\n const ry = box.halfHeight();\n const rx = this.capRadius(box, ry, separator);\n const body = this.bodyPath(box, rx, ry);\n // Only the NEAR end cap is drawn: that single arc is what reads as \"tube\" rather than\n // \"stadium\", and a real cylinder hides the far one behind the body.\n const cap =\n 'M' +\n (box.x0 + rx) +\n ',' +\n box.y0 +\n ' A' +\n rx +\n ',' +\n ry +\n ' 0 0 1 ' +\n (box.x0 + rx) +\n ',' +\n box.y1;\n\n const anchor = node.firstChild;\n if (anchor === null || anchor.nextSibling === null) return;\n node.insertBefore(this.pathEl(fill, stroke, body, dash), anchor.nextSibling);\n node.insertBefore(this.pathEl('none', stroke, cap, dash), anchor.nextSibling.nextSibling);\n\n // The label is deliberately NOT nudged. QUEUE_LABEL_PREFIX already gives the node an empty\n // leading record field, so Graphviz has centred the text in the space to the RIGHT of where the\n // cap lands. Shifting it again double-counts that offset and pushes the longest line out\n // through the far end of the cylinder.\n }\n\n private bodyPath(box: Bounds, rx: number, ry: number): string {\n return (\n 'M' +\n (box.x0 + rx) +\n ',' +\n box.y0 +\n ' L' +\n (box.x1 - rx) +\n ',' +\n box.y0 +\n ' A' +\n rx +\n ',' +\n ry +\n ' 0 0 1 ' +\n (box.x1 - rx) +\n ',' +\n box.y1 +\n ' L' +\n (box.x0 + rx) +\n ',' +\n box.y1 +\n ' A' +\n rx +\n ',' +\n ry +\n ' 0 0 1 ' +\n (box.x0 + rx) +\n ',' +\n box.y0 +\n ' Z'\n );\n }\n\n /**\n * A box listing several queues is TALL, and a cap scaled off half-height alone would then reach\n * past the empty leading field and sit on top of the first characters of the label. Graphviz sizes\n * that field from the font, not from the label's height, so the separator is the only honest bound\n * on how far right the cap may go.\n */\n private capRadius(box: Bounds, ry: number, separator: number | null): number {\n const fromHeight = Math.max(6, ry * CAP_RATIO);\n if (separator === null) return fromHeight;\n return Math.max(6, Math.min(fromHeight, separator - box.x0));\n }\n\n /**\n * The x of the record's field separator — the VERTICAL polyline Graphviz draws between the empty\n * leading field and the label — or null if this node has none.\n */\n private separatorX(shapes: NodeListOf<Element>): number | null {\n for (const shape of Array.from(shapes)) {\n if (shape.tagName !== 'polyline') continue;\n const nums = (shape.getAttribute('points') ?? '').match(/-?[\\d.]+/g);\n if (nums === null || nums.length < 4) continue;\n const x = parseFloat(nums[0]);\n if (Math.abs(x - parseFloat(nums[2])) < 0.5) return x;\n }\n return null;\n }\n\n /** The union bounding box of some SVG shape elements, from their raw geometry attributes. */\n private boundsOf(shapes: NodeListOf<Element>): Bounds | null {\n const xs: number[] = [];\n const ys: number[] = [];\n for (const shape of Array.from(shapes)) {\n const pts = shape.getAttribute('points');\n const source = pts ?? shape.getAttribute('d') ?? '';\n const nums = source.match(/-?[\\d.]+/g);\n if (nums === null) continue;\n for (let n = 0; n + 1 < nums.length; n += 2) {\n xs.push(parseFloat(nums[n]));\n ys.push(parseFloat(nums[n + 1]));\n }\n }\n if (xs.length === 0) return null;\n return new Bounds(Math.min(...xs), Math.max(...xs), Math.min(...ys), Math.max(...ys));\n }\n\n private pathEl(fill: string, stroke: string, d: string, dash: string | null): SVGPathElement {\n const el = document.createElementNS(QueueCylinders.SVG_NS, 'path');\n el.setAttribute('fill', fill);\n el.setAttribute('stroke', stroke);\n if (dash !== null) el.setAttribute('stroke-dasharray', dash);\n el.setAttribute('d', d);\n return el;\n }\n}\n\n/** Shape adapter for the shared viewer controller; no separate runtime control state. */\nclass RuntimeImplementsPayload {\n constructor(\n readonly name: string,\n readonly node: SVGGElement,\n ) {}\n}\n\nclass RuntimeViewerBindingImpl implements RuntimeViewerBinding {\n prepare(svg: SVGSVGElement): void {\n new QueueCylinders().applyTo(svg);\n // Keep identity titles readable by shared controllers without native SVG tooltips.\n svg.querySelectorAll('g.node > title, g.edge > title').forEach((title) => {\n title.parentElement?.setAttribute('aria-label', title.textContent ?? '');\n const identity = document.createElement('title');\n identity.textContent = title.textContent;\n title.replaceWith(identity);\n });\n }\n implementsItem(name: string, node: SVGGElement): WpNodeMenuItem | null {\n if (\n !node.querySelector('text') ||\n !Array.from(node.querySelectorAll('text')).some((text) =>\n text.textContent?.startsWith('Implements ('),\n )\n )\n return null;\n return new WpNodeMenuItem('Implements', (): void => {\n document.dispatchEvent(\n new CustomEvent('wp-runtime-implements', {\n detail: new RuntimeImplementsPayload(name, node),\n }),\n );\n });\n }\n}\nwindow.__WP_RUNTIME__ = new RuntimeViewerBindingImpl();\n"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { RuntimeGraph } from './runtime-graph';
|
|
2
2
|
import { GraphRenderModel } from './graph-render-model';
|
|
3
3
|
import { RuntimeVizOptions } from './runtime-viz-options';
|
|
4
|
-
|
|
4
|
+
import type { RuntimeComparisonView } from './graph-render-model';
|
|
5
|
+
export { RuntimeVizOptions, RuntimePageKind } from './runtime-viz-options';
|
|
5
6
|
/** Build the Graphviz DOT for the runtime service graph. */
|
|
6
7
|
export declare function generateRuntimeDot(graph: RuntimeGraph, title?: string, options?: RuntimeVizOptions): string;
|
|
7
8
|
/** Capture synthetic drawable nodes and edges at their original emission sites. */
|
|
@@ -10,5 +11,9 @@ export interface RuntimeVisualizationPaths {
|
|
|
10
11
|
dotPath: string;
|
|
11
12
|
htmlPath: string;
|
|
12
13
|
}
|
|
13
|
-
/**
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Write the DOT + HTML renderings to tmp/webpieces/: `runtime-architecture.*` for the current graph,
|
|
16
|
+
* `runtime-architecture-goal.*` for the goal (#1239), so neither page ever overwrites the other.
|
|
17
|
+
* `comparison` is the Goal vs Current overlay the page carries (or why it is unavailable).
|
|
18
|
+
*/
|
|
19
|
+
export declare function writeRuntimeVisualization(graph: RuntimeGraph, workspaceRoot: string, title: string, options: RuntimeVizOptions, comparison: RuntimeComparisonView): RuntimeVisualizationPaths;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RuntimeVizOptions = void 0;
|
|
3
|
+
exports.RuntimePageKind = exports.RuntimeVizOptions = void 0;
|
|
4
4
|
exports.generateRuntimeDot = generateRuntimeDot;
|
|
5
5
|
exports.generateRuntimeRenderModel = generateRuntimeRenderModel;
|
|
6
6
|
exports.writeRuntimeVisualization = writeRuntimeVisualization;
|
|
@@ -67,6 +67,7 @@ const PAIR_SEP = '|';
|
|
|
67
67
|
const runtime_viz_options_1 = require("./runtime-viz-options");
|
|
68
68
|
var runtime_viz_options_2 = require("./runtime-viz-options");
|
|
69
69
|
Object.defineProperty(exports, "RuntimeVizOptions", { enumerable: true, get: function () { return runtime_viz_options_2.RuntimeVizOptions; } });
|
|
70
|
+
Object.defineProperty(exports, "RuntimePageKind", { enumerable: true, get: function () { return runtime_viz_options_2.RuntimePageKind; } });
|
|
70
71
|
/**
|
|
71
72
|
* The DISPLAY name of a project/service: scope stripped. LABELS ONLY.
|
|
72
73
|
*
|
|
@@ -176,7 +177,7 @@ function queueBoxDot(id, body, producers, consumers, model, queueKeys, level) {
|
|
|
176
177
|
* anything else stays separate, because merging it would assert a routing that does not exist.
|
|
177
178
|
*/
|
|
178
179
|
// webpieces-disable no-function-outside-class -- DOT string builder, matching getShortName in this file
|
|
179
|
-
function groupQueues(byQueue, graph) {
|
|
180
|
+
function groupQueues(byQueue, graph, tags) {
|
|
180
181
|
const groups = new Map();
|
|
181
182
|
// Sorted keys → the first member of every group, and therefore its node id, is deterministic.
|
|
182
183
|
for (const key of [...byQueue.keys()].sort()) {
|
|
@@ -189,6 +190,7 @@ function groupQueues(byQueue, graph) {
|
|
|
189
190
|
graph.queues[key].level,
|
|
190
191
|
producers.join(','),
|
|
191
192
|
consumers.join(','),
|
|
193
|
+
tags[key] ?? '',
|
|
192
194
|
].join(PAIR_SEP);
|
|
193
195
|
const existing = groups.get(mergeKey);
|
|
194
196
|
if (existing === undefined)
|
|
@@ -211,7 +213,7 @@ function groupQueues(byQueue, graph) {
|
|
|
211
213
|
* one is stuck) at a fraction of the node count.
|
|
212
214
|
*/
|
|
213
215
|
// webpieces-disable no-function-outside-class -- DOT string builder, matching getShortName in this file
|
|
214
|
-
function queuesDot(graph, hidden, model) {
|
|
216
|
+
function queuesDot(graph, hidden, model, options) {
|
|
215
217
|
const queued = graph.runtimeEdges.filter((e) => e.type === 'pubsub' && !hidden.has(e.from) && !hidden.has(e.to));
|
|
216
218
|
if (queued.length === 0)
|
|
217
219
|
return '';
|
|
@@ -234,7 +236,7 @@ function queuesDot(graph, hidden, model) {
|
|
|
234
236
|
const ends = byContract.get(api);
|
|
235
237
|
dot += queueBoxDot(`queue__${dotId(api)}`, `${(0, dot_syntax_1.recordValue)(getShortName(api))} queue`, [...ends.producers].sort(), [...ends.consumers].sort(), model, [`queue:${api}`], graph.contractQueues[api].level);
|
|
236
238
|
}
|
|
237
|
-
for (const group of groupQueues(byQueue, graph)) {
|
|
239
|
+
for (const group of groupQueues(byQueue, graph, options.queueGroupTags)) {
|
|
238
240
|
const body = group.members
|
|
239
241
|
.map((key) => queueLine(key, graph.queues[key]))
|
|
240
242
|
.join('\\n');
|
|
@@ -485,7 +487,7 @@ function generateRuntimeRenderModel(graph, title = 'WebPieces Runtime Architectu
|
|
|
485
487
|
continue;
|
|
486
488
|
dot += model.edge(edge.from, edge.to, edgeDot(edge));
|
|
487
489
|
}
|
|
488
|
-
dot += queuesDot(graph, hidden, model);
|
|
490
|
+
dot += queuesDot(graph, hidden, model, options);
|
|
489
491
|
dot += remoteServicesDot(graph, hidden, model);
|
|
490
492
|
dot += triggerDot(graph, hidden, model);
|
|
491
493
|
if (options.showExternalNodes) {
|
|
@@ -495,7 +497,7 @@ function generateRuntimeRenderModel(graph, title = 'WebPieces Runtime Architectu
|
|
|
495
497
|
model.bands = adapter.levelBands(model);
|
|
496
498
|
const footerStart = dot.length;
|
|
497
499
|
dot += '\n labelloc="t";\n';
|
|
498
|
-
dot += ` label="${(0, dot_syntax_1.dotValue)(title)}\\n(from
|
|
500
|
+
dot += ` label="${(0, dot_syntax_1.dotValue)(title)}\\n(from ${(0, dot_syntax_1.dotValue)(options.source())})";\n`;
|
|
499
501
|
dot += ' fontsize=20;\n';
|
|
500
502
|
dot += '}\n';
|
|
501
503
|
// Nothing downstream parses this DOT until a human opens the page, so parse-shape is checked
|
|
@@ -509,16 +511,22 @@ function generateRuntimeRenderModel(graph, title = 'WebPieces Runtime Architectu
|
|
|
509
511
|
(0, dot_syntax_1.assertValidDot)(model.fullDot, 'runtime-architecture.dot');
|
|
510
512
|
return model;
|
|
511
513
|
}
|
|
512
|
-
/**
|
|
513
|
-
|
|
514
|
+
/**
|
|
515
|
+
* Write the DOT + HTML renderings to tmp/webpieces/: `runtime-architecture.*` for the current graph,
|
|
516
|
+
* `runtime-architecture-goal.*` for the goal (#1239), so neither page ever overwrites the other.
|
|
517
|
+
* `comparison` is the Goal vs Current overlay the page carries (or why it is unavailable).
|
|
518
|
+
*/
|
|
519
|
+
function writeRuntimeVisualization(graph, workspaceRoot, title, options, comparison) {
|
|
514
520
|
const outputDir = path.join(workspaceRoot, 'tmp', 'webpieces');
|
|
515
521
|
if (!fs.existsSync(outputDir))
|
|
516
522
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
517
523
|
const model = generateRuntimeRenderModel(graph, title, options);
|
|
524
|
+
model.comparison = comparison;
|
|
518
525
|
const dot = model.fullDot;
|
|
519
|
-
const
|
|
526
|
+
const base = options.page === runtime_viz_options_1.RuntimePageKind.GOAL ? 'runtime-architecture-goal' : 'runtime-architecture';
|
|
527
|
+
const dotPath = path.join(outputDir, `${base}.dot`);
|
|
520
528
|
fs.writeFileSync(dotPath, dot, 'utf-8');
|
|
521
|
-
const htmlPath = path.join(outputDir,
|
|
529
|
+
const htmlPath = path.join(outputDir, `${base}.html`);
|
|
522
530
|
fs.writeFileSync(htmlPath, new runtime_html_page_1.RuntimeHtmlPage().render(model, title, graph, options), 'utf-8');
|
|
523
531
|
return { dotPath, htmlPath };
|
|
524
532
|
}
|