@webpieces/nx-webpieces-rules 0.4.872 → 0.4.874
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 +31 -18
- package/package.json +7 -7
- package/src/executors/visualize/executor.d.ts +17 -3
- package/src/executors/visualize/executor.js +53 -33
- package/src/executors/visualize/executor.js.map +1 -1
- package/src/lib/graph-color-modes.d.ts +56 -34
- package/src/lib/graph-color-modes.js +111 -100
- package/src/lib/graph-color-modes.js.map +1 -1
- package/src/lib/graph-filter.client.d.ts +13 -2
- package/src/lib/graph-filter.client.js +27 -7
- package/src/lib/graph-filter.client.js.map +1 -1
- package/src/lib/graph-impact.d.ts +37 -3
- package/src/lib/graph-impact.js +42 -11
- package/src/lib/graph-impact.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-level-bands.d.ts +8 -0
- package/src/lib/graph-level-bands.js +13 -1
- package/src/lib/graph-level-bands.js.map +1 -1
- package/src/lib/graph-node-menu.js +10 -108
- package/src/lib/graph-node-menu.js.map +1 -1
- package/src/lib/graph-page-shell.d.ts +31 -1
- package/src/lib/graph-page-shell.js +75 -7
- package/src/lib/graph-page-shell.js.map +1 -1
- package/src/lib/graph-page-styles.d.ts +14 -3
- package/src/lib/graph-page-styles.js +89 -18
- package/src/lib/graph-page-styles.js.map +1 -1
- package/src/lib/graph-render-model.d.ts +14 -6
- package/src/lib/graph-render-model.js +22 -8
- package/src/lib/graph-render-model.js.map +1 -1
- package/src/lib/graph-visualizer.client.d.ts +82 -5
- package/src/lib/graph-visualizer.client.js +351 -23
- 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
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Graph color modes (#1155)
|
|
3
|
+
* Graph color modes (#1155, restyled by #1158)
|
|
4
4
|
*
|
|
5
5
|
* The architecture graph answers ONE question at a time instead of asking every box to encode two
|
|
6
6
|
* (fill = framework AND border = role). Each box is emitted once per mode, so the page can switch
|
|
7
|
-
* modes and re-render without regenerating anything
|
|
7
|
+
* modes and re-render without regenerating anything. Every mode writes the SAME three lines on a box
|
|
8
|
+
* (level + name, role, every framework tag); only the color changes:
|
|
8
9
|
*
|
|
9
|
-
* - RUNTIME "where the code can run".
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
10
|
+
* - RUNTIME "where the code can run". One runtime is a solid fill. One runtime plus a
|
|
11
|
+
* specialization (angular/react inside browser, express inside node) is NESTED: an
|
|
12
|
+
* outer frame in the base color around an inner rounded box in the specialization's
|
|
13
|
+
* color, carrying the text. Several runtimes are full-height vertical stripes in the
|
|
14
|
+
* fixed order browser | node | react-native, with the text written across them. The
|
|
15
|
+
* dependency rule becomes visual: a box may depend on a box carrying every color it has.
|
|
15
16
|
* - ARCHITECTURE "servers · clients · APIs". A solid fill by ROLE; framework color is not shown.
|
|
16
17
|
* - IMPACT "what this branch touches". Projects owning a changed file are solid amber
|
|
17
18
|
* ("touched"); the rest of nx's affected set is light amber ("affected": their ci
|
|
@@ -19,10 +20,10 @@
|
|
|
19
20
|
* affected is light slate with a dashed border ("build input": compiled or restored
|
|
20
21
|
* from cache, unchanged); everything else is grey. Which box is which is only known
|
|
21
22
|
* per branch, so every box carries all four variants and the page picks one from the
|
|
22
|
-
* sidecar (graph-impact.ts).
|
|
23
|
+
* sidecar (graph-impact.ts). The state is never written on the box: color + legend.
|
|
23
24
|
*/
|
|
24
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.NodeModeStyler = exports.LegendFacts = exports.NodeModeDots = exports.NodeFacts = exports.
|
|
26
|
+
exports.NodeModeStyler = exports.LegendFacts = exports.NodeModeDots = exports.NodeFacts = exports.IMPACT_UNTOUCHED = exports.IMPACT_BUILD_INPUT_BORDER = exports.IMPACT_BUILD_INPUT = exports.IMPACT_AFFECTED = exports.IMPACT_TOUCHED = exports.ROLE_STYLES = exports.RoleStyle = exports.STRIPED_CLASS = exports.NO_RUNTIME_COLOR = exports.FRAMEWORK_ORDER = exports.BASE_ORDER = exports.FRAMEWORK_STYLES = exports.FrameworkStyle = exports.LIGHT_TEXT = exports.DARK_TEXT = exports.GRAPH_MODES = exports.ModeInfo = exports.GraphMode = void 0;
|
|
26
27
|
const rules_sdk_1 = require("@webpieces/rules-sdk");
|
|
27
28
|
const dot_syntax_1 = require("./dot-syntax");
|
|
28
29
|
var GraphMode;
|
|
@@ -31,7 +32,7 @@ var GraphMode;
|
|
|
31
32
|
GraphMode["ARCHITECTURE"] = "architecture";
|
|
32
33
|
GraphMode["IMPACT"] = "impact";
|
|
33
34
|
})(GraphMode || (exports.GraphMode = GraphMode = {}));
|
|
34
|
-
/** One selectable mode as the drawer
|
|
35
|
+
/** One selectable mode as the drawer's Color-by pulldown shows it. */
|
|
35
36
|
class ModeInfo {
|
|
36
37
|
mode;
|
|
37
38
|
name;
|
|
@@ -49,16 +50,25 @@ exports.GRAPH_MODES = [
|
|
|
49
50
|
new ModeInfo(GraphMode.ARCHITECTURE, 'Architecture', 'servers · clients · APIs'),
|
|
50
51
|
new ModeInfo(GraphMode.IMPACT, 'Impact', 'what this branch touches'),
|
|
51
52
|
];
|
|
52
|
-
/**
|
|
53
|
+
/** Text on a light fill. */
|
|
54
|
+
exports.DARK_TEXT = '#1a1c22';
|
|
55
|
+
/** Text on a dark fill. */
|
|
56
|
+
exports.LIGHT_TEXT = '#ffffff';
|
|
57
|
+
/**
|
|
58
|
+
* A framework value's color, the text color that reads on it, and the BASE runtime it is drawn
|
|
59
|
+
* inside (itself, for a base).
|
|
60
|
+
*/
|
|
53
61
|
class FrameworkStyle {
|
|
54
62
|
framework;
|
|
55
63
|
base;
|
|
56
64
|
color;
|
|
65
|
+
fontColor;
|
|
57
66
|
description;
|
|
58
|
-
constructor(framework, base, color, description) {
|
|
67
|
+
constructor(framework, base, color, fontColor, description) {
|
|
59
68
|
this.framework = framework;
|
|
60
69
|
this.base = base;
|
|
61
70
|
this.color = color;
|
|
71
|
+
this.fontColor = fontColor;
|
|
62
72
|
this.description = description;
|
|
63
73
|
}
|
|
64
74
|
isBase() {
|
|
@@ -69,20 +79,38 @@ exports.FrameworkStyle = FrameworkStyle;
|
|
|
69
79
|
/**
|
|
70
80
|
* Keyed by the shared vocabulary, so a framework added to KNOWN_FRAMEWORKS without a color here is a
|
|
71
81
|
* COMPILE error — not a box silently painted grey and missing from the legend, which is exactly how
|
|
72
|
-
* react-native shipped (#1155).
|
|
82
|
+
* react-native shipped (#1155). Every base is mid-light, so dark text reads on every stripe.
|
|
73
83
|
*/
|
|
74
84
|
exports.FRAMEWORK_STYLES = {
|
|
75
|
-
browser: new FrameworkStyle('browser', 'browser', '#
|
|
76
|
-
node: new FrameworkStyle('node', 'node', '#
|
|
77
|
-
'react-native': new FrameworkStyle('react-native', 'react-native', '#
|
|
78
|
-
angular: new FrameworkStyle('angular', 'browser', '#
|
|
79
|
-
react: new FrameworkStyle('react', 'browser', '#
|
|
80
|
-
express: new FrameworkStyle('express', 'node', '#
|
|
85
|
+
browser: new FrameworkStyle('browser', 'browser', '#7d8cf2', exports.DARK_TEXT, 'browser base runtime'),
|
|
86
|
+
node: new FrameworkStyle('node', 'node', '#6fcf8a', exports.DARK_TEXT, 'node base runtime'),
|
|
87
|
+
'react-native': new FrameworkStyle('react-native', 'react-native', '#34b8a6', exports.DARK_TEXT, 'its own runtime, not a browser'),
|
|
88
|
+
angular: new FrameworkStyle('angular', 'browser', '#c8243f', exports.LIGHT_TEXT, 'inside browser'),
|
|
89
|
+
react: new FrameworkStyle('react', 'browser', '#7fd8ff', exports.DARK_TEXT, 'inside browser'),
|
|
90
|
+
express: new FrameworkStyle('express', 'node', '#2e7d4f', exports.LIGHT_TEXT, 'inside node'),
|
|
81
91
|
};
|
|
82
92
|
/** Stripe order, left to right. Fixed, so the same set always reads the same way. */
|
|
83
93
|
exports.BASE_ORDER = ['browser', 'node', 'react-native'];
|
|
94
|
+
/**
|
|
95
|
+
* The Filter popover's Runtime chips, and the order line 3 of a box lists framework tags in: the
|
|
96
|
+
* bases first, then the specializations.
|
|
97
|
+
*/
|
|
98
|
+
exports.FRAMEWORK_ORDER = [
|
|
99
|
+
'browser',
|
|
100
|
+
'node',
|
|
101
|
+
'react-native',
|
|
102
|
+
'angular',
|
|
103
|
+
'react',
|
|
104
|
+
'express',
|
|
105
|
+
];
|
|
84
106
|
/** A box with no known framework tag. */
|
|
85
107
|
exports.NO_RUNTIME_COLOR = '#e4e6ec';
|
|
108
|
+
/** The class Graphviz stamps on a multi-runtime box's `<g>`: its outline is its LAST shape. */
|
|
109
|
+
exports.STRIPED_CLASS = 'wp-striped';
|
|
110
|
+
/** Margin of base color around a specialization's inner box. */
|
|
111
|
+
const NEST_PAD = 5;
|
|
112
|
+
/** Padding between the inner box's edge and its text. */
|
|
113
|
+
const INNER_PAD = 6;
|
|
86
114
|
/** A role's solid fill and the text color that stays readable on it. */
|
|
87
115
|
class RoleStyle {
|
|
88
116
|
role;
|
|
@@ -97,16 +125,19 @@ class RoleStyle {
|
|
|
97
125
|
}
|
|
98
126
|
}
|
|
99
127
|
exports.RoleStyle = RoleStyle;
|
|
100
|
-
/**
|
|
128
|
+
/**
|
|
129
|
+
* Every role role-resolver knows, in legend order (runnable things first) — also the Filter popover's
|
|
130
|
+
* Role chips. `bundle` is indigo so no box color equals the page's violet accent.
|
|
131
|
+
*/
|
|
101
132
|
exports.ROLE_STYLES = [
|
|
102
|
-
new RoleStyle('server', '#4caf50',
|
|
103
|
-
new RoleStyle('client', '#e5533d',
|
|
104
|
-
new RoleStyle('app', '#1e88e5',
|
|
105
|
-
new RoleStyle('bundle', '#
|
|
106
|
-
new RoleStyle('api-lib', '#f08a24',
|
|
107
|
-
new RoleStyle('api-client', '#1a9aa6',
|
|
108
|
-
new RoleStyle('designed-lib', '#7d8597',
|
|
109
|
-
new RoleStyle('lib', '#d7dae2',
|
|
133
|
+
new RoleStyle('server', '#4caf50', exports.LIGHT_TEXT, 'runnable server'),
|
|
134
|
+
new RoleStyle('client', '#e5533d', exports.LIGHT_TEXT, 'browser or mobile client app'),
|
|
135
|
+
new RoleStyle('app', '#1e88e5', exports.LIGHT_TEXT, 'runnable non-HTTP app'),
|
|
136
|
+
new RoleStyle('bundle', '#4b44c8', exports.LIGHT_TEXT, 'bundles several apps'),
|
|
137
|
+
new RoleStyle('api-lib', '#f08a24', exports.DARK_TEXT, 'contract + DTOs'),
|
|
138
|
+
new RoleStyle('api-client', '#1a9aa6', exports.LIGHT_TEXT, 'contract + SDK implementation'),
|
|
139
|
+
new RoleStyle('designed-lib', '#7d8597', exports.LIGHT_TEXT, 'library with a generated design'),
|
|
140
|
+
new RoleStyle('lib', '#d7dae2', exports.DARK_TEXT, 'plain library'),
|
|
110
141
|
];
|
|
111
142
|
/** The four impact shades (graph-impact.ts decides which box gets which). */
|
|
112
143
|
exports.IMPACT_TOUCHED = '#f5a524';
|
|
@@ -114,19 +145,8 @@ exports.IMPACT_AFFECTED = '#fde3b0';
|
|
|
114
145
|
exports.IMPACT_BUILD_INPUT = '#e3e9f2';
|
|
115
146
|
exports.IMPACT_BUILD_INPUT_BORDER = '#7c8aa3';
|
|
116
147
|
exports.IMPACT_UNTOUCHED = '#eef0f4';
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
/** Height of each stripe band above and below the plate. */
|
|
120
|
-
const STRIPE_HEIGHT = 16;
|
|
121
|
-
/** Margin of base color around a specialization's inset (inside one stripe band). */
|
|
122
|
-
const INSET_PAD = 4;
|
|
123
|
-
/** Padding around the text on the plate. */
|
|
124
|
-
const PLATE_PAD = 4;
|
|
125
|
-
/** No stripe narrower than this, however short the name. */
|
|
126
|
-
const MIN_STRIPE_WIDTH = 28;
|
|
127
|
-
/** Rough Arial 14 advance, used only to size the stripes so they span the text evenly. */
|
|
128
|
-
const CHAR_WIDTH = 7.5;
|
|
129
|
-
/** What a box's per-mode rendering is computed from. */
|
|
148
|
+
const IMPACT_UNTOUCHED_TEXT = '#6b7180';
|
|
149
|
+
/** What a box's per-mode rendering — and the page's Filter — is computed from. */
|
|
130
150
|
class NodeFacts {
|
|
131
151
|
nodeId;
|
|
132
152
|
shortName;
|
|
@@ -204,7 +224,7 @@ class NodeModeStyler {
|
|
|
204
224
|
return undefined;
|
|
205
225
|
}
|
|
206
226
|
dots(facts) {
|
|
207
|
-
return new NodeModeDots(this.runtime(facts), this.
|
|
227
|
+
return new NodeModeDots(this.runtime(facts), this.plain(facts, this.roleStyle(facts.role).fill, this.roleStyle(facts.role).fontColor, ''), this.plain(facts, exports.IMPACT_TOUCHED, exports.DARK_TEXT, ''), this.plain(facts, exports.IMPACT_AFFECTED, exports.DARK_TEXT, `, color="${exports.IMPACT_TOUCHED}", penwidth=2`), this.plain(facts, exports.IMPACT_BUILD_INPUT, exports.DARK_TEXT, `, color="${exports.IMPACT_BUILD_INPUT_BORDER}", penwidth=1.5`, 'filled,dashed'), this.plain(facts, exports.IMPACT_UNTOUCHED, IMPACT_UNTOUCHED_TEXT, ', color="#b4b9c4"'));
|
|
208
228
|
}
|
|
209
229
|
/** Fold one drawn box into the legend facts. */
|
|
210
230
|
record(legend, facts) {
|
|
@@ -221,40 +241,25 @@ class NodeModeStyler {
|
|
|
221
241
|
if (bases.length === 0)
|
|
222
242
|
legend.noRuntime = true;
|
|
223
243
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
const envs = facts.frameworks.length === 0 ? 'no framework tag' : facts.frameworks.join('+');
|
|
235
|
-
return `L${facts.level} · ${envs}`;
|
|
236
|
-
}
|
|
237
|
-
architectureAttrs(facts) {
|
|
238
|
-
const style = this.roleStyle(facts.role);
|
|
239
|
-
return `style="filled", fillcolor="${style.fill}", fontcolor="${style.fontColor}"`;
|
|
244
|
+
/**
|
|
245
|
+
* Line 3 of every box: every framework tag, bases before specializations, any tag outside the
|
|
246
|
+
* shared vocabulary last (it still runs somewhere somebody declared).
|
|
247
|
+
*/
|
|
248
|
+
frameworkLine(frameworks) {
|
|
249
|
+
if (frameworks.length === 0)
|
|
250
|
+
return 'no framework tag';
|
|
251
|
+
const known = exports.FRAMEWORK_ORDER.filter((framework) => frameworks.includes(framework));
|
|
252
|
+
const unknown = frameworks.filter((framework) => this.styleOf(framework) === undefined);
|
|
253
|
+
return [...known, ...unknown].join(' · ');
|
|
240
254
|
}
|
|
241
255
|
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* meta across all of them, and the same stripes again. The stripes and insets stay visible above
|
|
246
|
-
* and below the text, and the text never straddles two colors.
|
|
256
|
+
* The three lines, identical in every mode: `L3 name` (level dimmed, name bold), the role, and
|
|
257
|
+
* the framework tags. The level is dimmed by giving its text color an alpha channel, which
|
|
258
|
+
* Graphviz writes as `fill-opacity`, so it dims on any fill.
|
|
247
259
|
*/
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (bases.length === 0)
|
|
252
|
-
return this.statement(facts, `style="filled", fillcolor="${exports.NO_RUNTIME_COLOR}"`, this.plainLabel(facts, meta));
|
|
253
|
-
const insets = bases.map((base) => this.specialization(base, facts.frameworks));
|
|
254
|
-
const plain = insets.every((inset) => inset === undefined);
|
|
255
|
-
if (bases.length === 1 && plain)
|
|
256
|
-
return this.statement(facts, this.stripeAttrs(bases), this.plainLabel(facts, meta));
|
|
257
|
-
return this.statement(facts, `style="filled", fillcolor="${exports.LABEL_PLATE}", margin=0`, `label=<${this.plateTable(facts, bases, insets, meta)}>`);
|
|
260
|
+
labelText(facts, fontColor) {
|
|
261
|
+
return (`<FONT COLOR="${fontColor}99">L${facts.level}</FONT>  <B>${(0, dot_syntax_1.htmlLabelText)(facts.shortName)}</B>` +
|
|
262
|
+
`<BR/>${(0, dot_syntax_1.htmlLabelText)(facts.role)}<BR/>${(0, dot_syntax_1.htmlLabelText)(this.frameworkLine(facts.frameworks))}`);
|
|
258
263
|
}
|
|
259
264
|
/** `filled` for one runtime; equal `striped` weights for several (the last takes the remainder). */
|
|
260
265
|
stripeAttrs(bases) {
|
|
@@ -263,36 +268,42 @@ class NodeModeStyler {
|
|
|
263
268
|
return `style="filled", fillcolor="${colors[0]}"`;
|
|
264
269
|
const share = (1 / colors.length).toFixed(3);
|
|
265
270
|
const weighted = colors.map((color, index) => index === colors.length - 1 ? color : `${color};${share}`);
|
|
266
|
-
return `style="striped", fillcolor="${weighted.join(':')}"`;
|
|
271
|
+
return `style="striped", fillcolor="${weighted.join(':')}", class="${exports.STRIPED_CLASS}"`;
|
|
272
|
+
}
|
|
273
|
+
statement(facts, attrs, label) {
|
|
274
|
+
return ` "${(0, dot_syntax_1.dotValue)(facts.nodeId)}" [${attrs}, label=<${label}>];\n`;
|
|
275
|
+
}
|
|
276
|
+
/** A solid fill, the three lines on it. `extra` carries border attributes. */
|
|
277
|
+
plain(facts, fill, fontColor, extra, style = 'filled') {
|
|
278
|
+
return this.statement(facts, `style="${style}", fillcolor="${fill}", fontcolor="${fontColor}"${extra}`, this.labelText(facts, fontColor));
|
|
267
279
|
}
|
|
268
280
|
/**
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
281
|
+
* Runtime mode. No runtime, or one runtime with no specialization: a solid fill. One runtime with a
|
|
282
|
+
* specialization: NESTED. Several runtimes: full-height stripes with the text across them (a
|
|
283
|
+
* specialization on such a box shows in line 3 only).
|
|
272
284
|
*/
|
|
273
|
-
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
.
|
|
279
|
-
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
`<TR>${band}</TR>` +
|
|
285
|
-
'</TABLE>');
|
|
285
|
+
runtime(facts) {
|
|
286
|
+
const bases = this.bases(facts.frameworks);
|
|
287
|
+
if (bases.length === 0)
|
|
288
|
+
return this.plain(facts, exports.NO_RUNTIME_COLOR, exports.DARK_TEXT, '');
|
|
289
|
+
if (bases.length > 1)
|
|
290
|
+
return this.statement(facts, `${this.stripeAttrs(bases)}, fontcolor="${exports.DARK_TEXT}"`, this.labelText(facts, exports.DARK_TEXT));
|
|
291
|
+
const base = exports.FRAMEWORK_STYLES[bases[0]];
|
|
292
|
+
const inner = this.specialization(bases[0], facts.frameworks);
|
|
293
|
+
if (inner === undefined)
|
|
294
|
+
return this.plain(facts, base.color, base.fontColor, '');
|
|
295
|
+
return this.statement(facts, `style="filled", fillcolor="${base.color}", fontcolor="${inner.fontColor}", margin=0`, this.nestedTable(base.color, inner, this.labelText(facts, inner.fontColor)));
|
|
286
296
|
}
|
|
287
|
-
/**
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
return (
|
|
294
|
-
`<
|
|
295
|
-
`<
|
|
297
|
+
/**
|
|
298
|
+
* An outer cell in the base color whose padding is the visible frame, holding an inner ROUNDED
|
|
299
|
+
* table in the specialization's color that carries the text. The node's own polygon stays its
|
|
300
|
+
* FIRST shape, so the hover glow and the lock outline land on the outer box only.
|
|
301
|
+
*/
|
|
302
|
+
nestedTable(base, inner, text) {
|
|
303
|
+
return ('<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" CELLPADDING="0">' +
|
|
304
|
+
`<TR><TD BGCOLOR="${base}" CELLPADDING="${NEST_PAD}">` +
|
|
305
|
+
`<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" CELLPADDING="${INNER_PAD}" BGCOLOR="${inner.color}" STYLE="rounded">` +
|
|
306
|
+
`<TR><TD>${text}</TD></TR></TABLE></TD></TR></TABLE>`);
|
|
296
307
|
}
|
|
297
308
|
}
|
|
298
309
|
exports.NodeModeStyler = NodeModeStyler;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-color-modes.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-color-modes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Graph color modes (#1155)\n *\n * The architecture graph answers ONE question at a time instead of asking every box to encode two\n * (fill = framework AND border = role). Each box is emitted once per mode, so the page can switch\n * modes and re-render without regenerating anything:\n *\n * - RUNTIME \"where the code can run\". Base runtimes are equal vertical stripes in the fixed\n * order browser | node | react-native; a specialization (angular/react inside\n * browser, express inside node) is an inset inside its base stripe. The dependency\n * rule becomes visual: a box may depend on a box carrying every color it has. The\n * name and meta sit on a light label PLATE across the middle, so they read on every\n * stripe combination while the stripes and insets stay visible above and below it.\n * - ARCHITECTURE \"servers · clients · APIs\". A solid fill by ROLE; framework color is not shown.\n * - IMPACT \"what this branch touches\". Projects owning a changed file are solid amber\n * (\"touched\"); the rest of nx's affected set is light amber (\"affected\": their ci\n * re-runs); every transitive dependency of the affected set that is not itself\n * affected is light slate with a dashed border (\"build input\": compiled or restored\n * from cache, unchanged); everything else is grey. Which box is which is only known\n * per branch, so every box carries all four variants and the page picks one from the\n * sidecar (graph-impact.ts).\n */\n\nimport { KNOWN_FRAMEWORKS, KnownFramework } from '@webpieces/rules-sdk';\nimport { dotValue, htmlLabelText } from './dot-syntax';\n\nexport enum GraphMode {\n RUNTIME = 'runtime',\n ARCHITECTURE = 'architecture',\n IMPACT = 'impact',\n}\n\n/** One selectable mode as the drawer and the node menu show it. */\nexport class ModeInfo {\n constructor(\n public readonly mode: GraphMode,\n public readonly name: string,\n public readonly subtitle: string,\n ) {}\n}\n\n/** In key order: `1` selects the first, `2` the second, `3` the third. */\nexport const GRAPH_MODES: readonly ModeInfo[] = [\n new ModeInfo(GraphMode.RUNTIME, 'Runtime', 'where the code can run'),\n new ModeInfo(GraphMode.ARCHITECTURE, 'Architecture', 'servers · clients · APIs'),\n new ModeInfo(GraphMode.IMPACT, 'Impact', 'what this branch touches'),\n];\n\n/** A framework value's color and the BASE runtime it is drawn inside (itself, for a base). */\nexport class FrameworkStyle {\n constructor(\n public readonly framework: KnownFramework,\n public readonly base: KnownFramework,\n public readonly color: string,\n public readonly description: string,\n ) {}\n\n isBase(): boolean {\n return this.framework === this.base;\n }\n}\n\n/**\n * Keyed by the shared vocabulary, so a framework added to KNOWN_FRAMEWORKS without a color here is a\n * COMPILE error — not a box silently painted grey and missing from the legend, which is exactly how\n * react-native shipped (#1155).\n */\nexport const FRAMEWORK_STYLES: Record<KnownFramework, FrameworkStyle> = {\n browser: new FrameworkStyle('browser', 'browser', '#b9a7e6', 'browser base runtime'),\n node: new FrameworkStyle('node', 'node', '#ffe07a', 'node base runtime'),\n 'react-native': new FrameworkStyle(\n 'react-native',\n 'react-native',\n '#7fd1c4',\n 'its own runtime, not a browser',\n ),\n angular: new FrameworkStyle('angular', 'browser', '#f59ab9', 'inside browser'),\n react: new FrameworkStyle('react', 'browser', '#8fd3f7', 'inside browser'),\n express: new FrameworkStyle('express', 'node', '#9fd8a3', 'inside node'),\n};\n\n/** Stripe order, left to right. Fixed, so the same set always reads the same way. */\nexport const BASE_ORDER: readonly KnownFramework[] = ['browser', 'node', 'react-native'];\n\n/** A box with no known framework tag. */\nexport const NO_RUNTIME_COLOR = '#e4e6ec';\n\n/** A role's solid fill and the text color that stays readable on it. */\nexport class RoleStyle {\n constructor(\n public readonly role: string,\n public readonly fill: string,\n public readonly fontColor: string,\n public readonly description: string,\n ) {}\n}\n\n/** Every role role-resolver knows, in legend order (runnable things first). */\nexport const ROLE_STYLES: readonly RoleStyle[] = [\n new RoleStyle('server', '#4caf50', '#ffffff', 'runnable server'),\n new RoleStyle('client', '#e5533d', '#ffffff', 'browser or mobile client app'),\n new RoleStyle('app', '#1e88e5', '#ffffff', 'runnable non-HTTP app'),\n new RoleStyle('bundle', '#7b3fa6', '#ffffff', 'bundles several apps'),\n new RoleStyle('api-lib', '#f08a24', '#1a1c22', 'contract + DTOs'),\n new RoleStyle('api-client', '#1a9aa6', '#ffffff', 'contract + SDK implementation'),\n new RoleStyle('designed-lib', '#7d8597', '#ffffff', 'library with a generated design'),\n new RoleStyle('lib', '#d7dae2', '#1a1c22', 'plain library'),\n];\n\n/** The four impact shades (graph-impact.ts decides which box gets which). */\nexport const IMPACT_TOUCHED = '#f5a524';\nexport const IMPACT_AFFECTED = '#fde3b0';\nexport const IMPACT_BUILD_INPUT = '#e3e9f2';\nexport const IMPACT_BUILD_INPUT_BORDER = '#7c8aa3';\nexport const IMPACT_UNTOUCHED = '#eef0f4';\n\n/** The light plate the name and meta sit on, across every stripe of a multi-color box. */\nexport const LABEL_PLATE = '#fbfbfd';\n/** Height of each stripe band above and below the plate. */\nconst STRIPE_HEIGHT = 16;\n/** Margin of base color around a specialization's inset (inside one stripe band). */\nconst INSET_PAD = 4;\n/** Padding around the text on the plate. */\nconst PLATE_PAD = 4;\n/** No stripe narrower than this, however short the name. */\nconst MIN_STRIPE_WIDTH = 28;\n/** Rough Arial 14 advance, used only to size the stripes so they span the text evenly. */\nconst CHAR_WIDTH = 7.5;\n\n/** What a box's per-mode rendering is computed from. */\nexport class NodeFacts {\n constructor(\n public readonly nodeId: string,\n public readonly shortName: string,\n public readonly level: number,\n public readonly role: string,\n public readonly frameworks: string[],\n ) {}\n}\n\n/** One box's DOT statement for every mode (and for each impact state). */\nexport class NodeModeDots {\n constructor(\n public readonly runtime: string,\n public readonly architecture: string,\n public readonly touched: string,\n public readonly affected: string,\n public readonly buildInput: string,\n public readonly untouched: string,\n ) {}\n}\n\n/** Which colors and roles the drawn projects actually use, so the legend lists exactly those. */\nexport class LegendFacts {\n frameworks: string[] = [];\n roles: string[] = [];\n multiRuntime = false;\n noRuntime = false;\n}\n\nexport class NodeModeStyler {\n styleOf(framework: string): FrameworkStyle | undefined {\n if (!(KNOWN_FRAMEWORKS as readonly string[]).includes(framework)) return undefined;\n return FRAMEWORK_STYLES[framework as KnownFramework];\n }\n\n roleStyle(role: string): RoleStyle {\n const style = ROLE_STYLES.find((candidate: RoleStyle): boolean => candidate.role === role);\n return style ?? (ROLE_STYLES.find((s: RoleStyle): boolean => s.role === 'lib') as RoleStyle);\n }\n\n /** Every role the renderer styles; a spec asserts this covers role-resolver's KNOWN_ROLES. */\n styledRoles(): string[] {\n return ROLE_STYLES.map((style: RoleStyle): string => style.role);\n }\n\n /** The base runtimes of a framework set, in stripe order (a specialization implies its base). */\n bases(frameworks: string[]): KnownFramework[] {\n const present = new Set<KnownFramework>();\n for (const framework of frameworks) {\n const style = this.styleOf(framework);\n if (style !== undefined) present.add(style.base);\n }\n return BASE_ORDER.filter((base: KnownFramework): boolean => present.has(base));\n }\n\n /** The specialization drawn inside `base`, if the set carries one. */\n specialization(base: KnownFramework, frameworks: string[]): FrameworkStyle | undefined {\n for (const framework of KNOWN_FRAMEWORKS) {\n const style = FRAMEWORK_STYLES[framework];\n if (style.isBase() || style.base !== base) continue;\n if (frameworks.includes(framework)) return style;\n }\n return undefined;\n }\n\n dots(facts: NodeFacts): NodeModeDots {\n return new NodeModeDots(\n this.runtime(facts),\n this.statement(facts, this.architectureAttrs(facts), this.plainLabel(facts, this.envMeta(facts))),\n this.statement(facts, `style=\"filled\", fillcolor=\"${IMPACT_TOUCHED}\"`, this.plainLabel(facts, 'touched')),\n this.statement(\n facts,\n `style=\"filled\", fillcolor=\"${IMPACT_AFFECTED}\", color=\"${IMPACT_TOUCHED}\", penwidth=2`,\n this.plainLabel(facts, 'affected'),\n ),\n this.statement(\n facts,\n `style=\"filled,dashed\", fillcolor=\"${IMPACT_BUILD_INPUT}\", color=\"${IMPACT_BUILD_INPUT_BORDER}\", penwidth=1.5`,\n this.plainLabel(facts, 'build input'),\n ),\n this.statement(\n facts,\n `style=\"filled\", fillcolor=\"${IMPACT_UNTOUCHED}\", color=\"#b4b9c4\", fontcolor=\"#6b7180\"`,\n this.plainLabel(facts, `L${facts.level}`),\n ),\n );\n }\n\n /** Fold one drawn box into the legend facts. */\n record(legend: LegendFacts, facts: NodeFacts): void {\n for (const framework of facts.frameworks) {\n if (this.styleOf(framework) !== undefined && !legend.frameworks.includes(framework))\n legend.frameworks.push(framework);\n }\n const role = this.roleStyle(facts.role).role;\n if (!legend.roles.includes(role)) legend.roles.push(role);\n const bases = this.bases(facts.frameworks);\n if (bases.length > 1) legend.multiRuntime = true;\n if (bases.length === 0) legend.noRuntime = true;\n }\n\n private statement(facts: NodeFacts, attrs: string, label: string): string {\n return ` \"${dotValue(facts.nodeId)}\" [${attrs}, ${label}];\\n`;\n }\n\n private plainLabel(facts: NodeFacts, meta: string): string {\n return `label=\"${dotValue(facts.shortName)}\\\\n${dotValue(meta)}\"`;\n }\n\n private runtimeMeta(facts: NodeFacts): string {\n return `L${facts.level} · ${facts.role}`;\n }\n\n private envMeta(facts: NodeFacts): string {\n const envs = facts.frameworks.length === 0 ? 'no framework tag' : facts.frameworks.join('+');\n return `L${facts.level} · ${envs}`;\n }\n\n private architectureAttrs(facts: NodeFacts): string {\n const style = this.roleStyle(facts.role);\n return `style=\"filled\", fillcolor=\"${style.fill}\", fontcolor=\"${style.fontColor}\"`;\n }\n\n /**\n * Runtime mode. A box in ONE base runtime with no specialization is a plain fill — its dark text\n * reads on any of the pastel base colors. Every other box (several runtimes, or a specialization)\n * is an HTML-like table of three rows: a band of equal stripes, a light PLATE carrying the name and\n * meta across all of them, and the same stripes again. The stripes and insets stay visible above\n * and below the text, and the text never straddles two colors.\n */\n private runtime(facts: NodeFacts): string {\n const bases = this.bases(facts.frameworks);\n const meta = this.runtimeMeta(facts);\n if (bases.length === 0)\n return this.statement(facts, `style=\"filled\", fillcolor=\"${NO_RUNTIME_COLOR}\"`, this.plainLabel(facts, meta));\n const insets = bases.map((base: KnownFramework) => this.specialization(base, facts.frameworks));\n const plain = insets.every((inset: FrameworkStyle | undefined): boolean => inset === undefined);\n if (bases.length === 1 && plain)\n return this.statement(facts, this.stripeAttrs(bases), this.plainLabel(facts, meta));\n return this.statement(\n facts,\n `style=\"filled\", fillcolor=\"${LABEL_PLATE}\", margin=0`,\n `label=<${this.plateTable(facts, bases, insets, meta)}>`,\n );\n }\n\n /** `filled` for one runtime; equal `striped` weights for several (the last takes the remainder). */\n stripeAttrs(bases: KnownFramework[]): string {\n const colors = bases.map((base: KnownFramework): string => FRAMEWORK_STYLES[base].color);\n if (colors.length === 1) return `style=\"filled\", fillcolor=\"${colors[0]}\"`;\n const share = (1 / colors.length).toFixed(3);\n const weighted = colors.map((color: string, index: number): string =>\n index === colors.length - 1 ? color : `${color};${share}`,\n );\n return `style=\"striped\", fillcolor=\"${weighted.join(':')}\"`;\n }\n\n /**\n * Stripe band / plate / stripe band. Every stripe cell asks for the same minimum width (an\n * estimate of the text's width split evenly), so the stripes come out equal and the plate spans\n * exactly their total.\n */\n private plateTable(\n facts: NodeFacts,\n bases: KnownFramework[],\n insets: (FrameworkStyle | undefined)[],\n meta: string,\n ): string {\n const chars = Math.max(facts.shortName.length, meta.length);\n const textWidth = Math.ceil(chars * CHAR_WIDTH) + 2 * PLATE_PAD;\n const stripeWidth = Math.max(MIN_STRIPE_WIDTH, Math.ceil(textWidth / bases.length));\n const band = bases\n .map((base: KnownFramework, index: number): string =>\n this.stripeCell(FRAMEWORK_STYLES[base].color, insets[index], stripeWidth),\n )\n .join('');\n const text = `${htmlLabelText(facts.shortName)}<BR/>${htmlLabelText(meta)}`;\n return (\n '<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">' +\n `<TR>${band}</TR>` +\n `<TR><TD COLSPAN=\"${bases.length}\" BGCOLOR=\"${LABEL_PLATE}\" CELLPADDING=\"${PLATE_PAD}\">${text}</TD></TR>` +\n `<TR>${band}</TR>` +\n '</TABLE>'\n );\n }\n\n /** One stripe of a band: the base color, with its specialization inset inside a margin of it. */\n private stripeCell(base: string, inset: FrameworkStyle | undefined, width: number): string {\n if (inset === undefined) return `<TD BGCOLOR=\"${base}\" WIDTH=\"${width}\" HEIGHT=\"${STRIPE_HEIGHT}\"></TD>`;\n const innerWidth = width - 2 * INSET_PAD;\n const innerHeight = STRIPE_HEIGHT - 2 * INSET_PAD;\n return (\n `<TD BGCOLOR=\"${base}\" CELLPADDING=\"${INSET_PAD}\">` +\n `<TABLE BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\" BGCOLOR=\"${inset.color}\" STYLE=\"rounded\">` +\n `<TR><TD WIDTH=\"${innerWidth}\" HEIGHT=\"${innerHeight}\"></TD></TR></TABLE></TD>`\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"graph-color-modes.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-color-modes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Graph color modes (#1155, restyled by #1158)\n *\n * The architecture graph answers ONE question at a time instead of asking every box to encode two\n * (fill = framework AND border = role). Each box is emitted once per mode, so the page can switch\n * modes and re-render without regenerating anything. Every mode writes the SAME three lines on a box\n * (level + name, role, every framework tag); only the color changes:\n *\n * - RUNTIME \"where the code can run\". One runtime is a solid fill. One runtime plus a\n * specialization (angular/react inside browser, express inside node) is NESTED: an\n * outer frame in the base color around an inner rounded box in the specialization's\n * color, carrying the text. Several runtimes are full-height vertical stripes in the\n * fixed order browser | node | react-native, with the text written across them. The\n * dependency rule becomes visual: a box may depend on a box carrying every color it has.\n * - ARCHITECTURE \"servers · clients · APIs\". A solid fill by ROLE; framework color is not shown.\n * - IMPACT \"what this branch touches\". Projects owning a changed file are solid amber\n * (\"touched\"); the rest of nx's affected set is light amber (\"affected\": their ci\n * re-runs); every transitive dependency of the affected set that is not itself\n * affected is light slate with a dashed border (\"build input\": compiled or restored\n * from cache, unchanged); everything else is grey. Which box is which is only known\n * per branch, so every box carries all four variants and the page picks one from the\n * sidecar (graph-impact.ts). The state is never written on the box: color + legend.\n */\n\nimport { KNOWN_FRAMEWORKS, KnownFramework } from '@webpieces/rules-sdk';\nimport { dotValue, htmlLabelText } from './dot-syntax';\n\nexport enum GraphMode {\n RUNTIME = 'runtime',\n ARCHITECTURE = 'architecture',\n IMPACT = 'impact',\n}\n\n/** One selectable mode as the drawer's Color-by pulldown shows it. */\nexport class ModeInfo {\n constructor(\n public readonly mode: GraphMode,\n public readonly name: string,\n public readonly subtitle: string,\n ) {}\n}\n\n/** In key order: `1` selects the first, `2` the second, `3` the third. */\nexport const GRAPH_MODES: readonly ModeInfo[] = [\n new ModeInfo(GraphMode.RUNTIME, 'Runtime', 'where the code can run'),\n new ModeInfo(GraphMode.ARCHITECTURE, 'Architecture', 'servers · clients · APIs'),\n new ModeInfo(GraphMode.IMPACT, 'Impact', 'what this branch touches'),\n];\n\n/** Text on a light fill. */\nexport const DARK_TEXT = '#1a1c22';\n/** Text on a dark fill. */\nexport const LIGHT_TEXT = '#ffffff';\n\n/**\n * A framework value's color, the text color that reads on it, and the BASE runtime it is drawn\n * inside (itself, for a base).\n */\nexport class FrameworkStyle {\n constructor(\n public readonly framework: KnownFramework,\n public readonly base: KnownFramework,\n public readonly color: string,\n public readonly fontColor: string,\n public readonly description: string,\n ) {}\n\n isBase(): boolean {\n return this.framework === this.base;\n }\n}\n\n/**\n * Keyed by the shared vocabulary, so a framework added to KNOWN_FRAMEWORKS without a color here is a\n * COMPILE error — not a box silently painted grey and missing from the legend, which is exactly how\n * react-native shipped (#1155). Every base is mid-light, so dark text reads on every stripe.\n */\nexport const FRAMEWORK_STYLES: Record<KnownFramework, FrameworkStyle> = {\n browser: new FrameworkStyle('browser', 'browser', '#7d8cf2', DARK_TEXT, 'browser base runtime'),\n node: new FrameworkStyle('node', 'node', '#6fcf8a', DARK_TEXT, 'node base runtime'),\n 'react-native': new FrameworkStyle(\n 'react-native',\n 'react-native',\n '#34b8a6',\n DARK_TEXT,\n 'its own runtime, not a browser',\n ),\n angular: new FrameworkStyle('angular', 'browser', '#c8243f', LIGHT_TEXT, 'inside browser'),\n react: new FrameworkStyle('react', 'browser', '#7fd8ff', DARK_TEXT, 'inside browser'),\n express: new FrameworkStyle('express', 'node', '#2e7d4f', LIGHT_TEXT, 'inside node'),\n};\n\n/** Stripe order, left to right. Fixed, so the same set always reads the same way. */\nexport const BASE_ORDER: readonly KnownFramework[] = ['browser', 'node', 'react-native'];\n\n/**\n * The Filter popover's Runtime chips, and the order line 3 of a box lists framework tags in: the\n * bases first, then the specializations.\n */\nexport const FRAMEWORK_ORDER: readonly KnownFramework[] = [\n 'browser',\n 'node',\n 'react-native',\n 'angular',\n 'react',\n 'express',\n];\n\n/** A box with no known framework tag. */\nexport const NO_RUNTIME_COLOR = '#e4e6ec';\n\n/** The class Graphviz stamps on a multi-runtime box's `<g>`: its outline is its LAST shape. */\nexport const STRIPED_CLASS = 'wp-striped';\n\n/** Margin of base color around a specialization's inner box. */\nconst NEST_PAD = 5;\n/** Padding between the inner box's edge and its text. */\nconst INNER_PAD = 6;\n\n/** A role's solid fill and the text color that stays readable on it. */\nexport class RoleStyle {\n constructor(\n public readonly role: string,\n public readonly fill: string,\n public readonly fontColor: string,\n public readonly description: string,\n ) {}\n}\n\n/**\n * Every role role-resolver knows, in legend order (runnable things first) — also the Filter popover's\n * Role chips. `bundle` is indigo so no box color equals the page's violet accent.\n */\nexport const ROLE_STYLES: readonly RoleStyle[] = [\n new RoleStyle('server', '#4caf50', LIGHT_TEXT, 'runnable server'),\n new RoleStyle('client', '#e5533d', LIGHT_TEXT, 'browser or mobile client app'),\n new RoleStyle('app', '#1e88e5', LIGHT_TEXT, 'runnable non-HTTP app'),\n new RoleStyle('bundle', '#4b44c8', LIGHT_TEXT, 'bundles several apps'),\n new RoleStyle('api-lib', '#f08a24', DARK_TEXT, 'contract + DTOs'),\n new RoleStyle('api-client', '#1a9aa6', LIGHT_TEXT, 'contract + SDK implementation'),\n new RoleStyle('designed-lib', '#7d8597', LIGHT_TEXT, 'library with a generated design'),\n new RoleStyle('lib', '#d7dae2', DARK_TEXT, 'plain library'),\n];\n\n/** The four impact shades (graph-impact.ts decides which box gets which). */\nexport const IMPACT_TOUCHED = '#f5a524';\nexport const IMPACT_AFFECTED = '#fde3b0';\nexport const IMPACT_BUILD_INPUT = '#e3e9f2';\nexport const IMPACT_BUILD_INPUT_BORDER = '#7c8aa3';\nexport const IMPACT_UNTOUCHED = '#eef0f4';\nconst IMPACT_UNTOUCHED_TEXT = '#6b7180';\n\n/** What a box's per-mode rendering — and the page's Filter — is computed from. */\nexport class NodeFacts {\n constructor(\n public readonly nodeId: string,\n public readonly shortName: string,\n public readonly level: number,\n public readonly role: string,\n public readonly frameworks: string[],\n ) {}\n}\n\n/** One box's DOT statement for every mode (and for each impact state). */\nexport class NodeModeDots {\n constructor(\n public readonly runtime: string,\n public readonly architecture: string,\n public readonly touched: string,\n public readonly affected: string,\n public readonly buildInput: string,\n public readonly untouched: string,\n ) {}\n}\n\n/** Which colors and roles the drawn projects actually use, so the legend lists exactly those. */\nexport class LegendFacts {\n frameworks: string[] = [];\n roles: string[] = [];\n multiRuntime = false;\n noRuntime = false;\n}\n\nexport class NodeModeStyler {\n styleOf(framework: string): FrameworkStyle | undefined {\n if (!(KNOWN_FRAMEWORKS as readonly string[]).includes(framework)) return undefined;\n return FRAMEWORK_STYLES[framework as KnownFramework];\n }\n\n roleStyle(role: string): RoleStyle {\n const style = ROLE_STYLES.find((candidate: RoleStyle): boolean => candidate.role === role);\n return style ?? (ROLE_STYLES.find((s: RoleStyle): boolean => s.role === 'lib') as RoleStyle);\n }\n\n /** Every role the renderer styles; a spec asserts this covers role-resolver's KNOWN_ROLES. */\n styledRoles(): string[] {\n return ROLE_STYLES.map((style: RoleStyle): string => style.role);\n }\n\n /** The base runtimes of a framework set, in stripe order (a specialization implies its base). */\n bases(frameworks: string[]): KnownFramework[] {\n const present = new Set<KnownFramework>();\n for (const framework of frameworks) {\n const style = this.styleOf(framework);\n if (style !== undefined) present.add(style.base);\n }\n return BASE_ORDER.filter((base: KnownFramework): boolean => present.has(base));\n }\n\n /** The specialization drawn inside `base`, if the set carries one. */\n specialization(base: KnownFramework, frameworks: string[]): FrameworkStyle | undefined {\n for (const framework of KNOWN_FRAMEWORKS) {\n const style = FRAMEWORK_STYLES[framework];\n if (style.isBase() || style.base !== base) continue;\n if (frameworks.includes(framework)) return style;\n }\n return undefined;\n }\n\n dots(facts: NodeFacts): NodeModeDots {\n return new NodeModeDots(\n this.runtime(facts),\n this.plain(facts, this.roleStyle(facts.role).fill, this.roleStyle(facts.role).fontColor, ''),\n this.plain(facts, IMPACT_TOUCHED, DARK_TEXT, ''),\n this.plain(facts, IMPACT_AFFECTED, DARK_TEXT, `, color=\"${IMPACT_TOUCHED}\", penwidth=2`),\n this.plain(\n facts,\n IMPACT_BUILD_INPUT,\n DARK_TEXT,\n `, color=\"${IMPACT_BUILD_INPUT_BORDER}\", penwidth=1.5`,\n 'filled,dashed',\n ),\n this.plain(facts, IMPACT_UNTOUCHED, IMPACT_UNTOUCHED_TEXT, ', color=\"#b4b9c4\"'),\n );\n }\n\n /** Fold one drawn box into the legend facts. */\n record(legend: LegendFacts, facts: NodeFacts): void {\n for (const framework of facts.frameworks) {\n if (this.styleOf(framework) !== undefined && !legend.frameworks.includes(framework))\n legend.frameworks.push(framework);\n }\n const role = this.roleStyle(facts.role).role;\n if (!legend.roles.includes(role)) legend.roles.push(role);\n const bases = this.bases(facts.frameworks);\n if (bases.length > 1) legend.multiRuntime = true;\n if (bases.length === 0) legend.noRuntime = true;\n }\n\n /**\n * Line 3 of every box: every framework tag, bases before specializations, any tag outside the\n * shared vocabulary last (it still runs somewhere somebody declared).\n */\n frameworkLine(frameworks: string[]): string {\n if (frameworks.length === 0) return 'no framework tag';\n const known = FRAMEWORK_ORDER.filter((framework: KnownFramework): boolean =>\n frameworks.includes(framework),\n );\n const unknown = frameworks.filter((framework: string): boolean => this.styleOf(framework) === undefined);\n return [...known, ...unknown].join(' · ');\n }\n\n /**\n * The three lines, identical in every mode: `L3 name` (level dimmed, name bold), the role, and\n * the framework tags. The level is dimmed by giving its text color an alpha channel, which\n * Graphviz writes as `fill-opacity`, so it dims on any fill.\n */\n labelText(facts: NodeFacts, fontColor: string): string {\n return (\n `<FONT COLOR=\"${fontColor}99\">L${facts.level}</FONT>  <B>${htmlLabelText(facts.shortName)}</B>` +\n `<BR/>${htmlLabelText(facts.role)}<BR/>${htmlLabelText(this.frameworkLine(facts.frameworks))}`\n );\n }\n\n /** `filled` for one runtime; equal `striped` weights for several (the last takes the remainder). */\n stripeAttrs(bases: KnownFramework[]): string {\n const colors = bases.map((base: KnownFramework): string => FRAMEWORK_STYLES[base].color);\n if (colors.length === 1) return `style=\"filled\", fillcolor=\"${colors[0]}\"`;\n const share = (1 / colors.length).toFixed(3);\n const weighted = colors.map((color: string, index: number): string =>\n index === colors.length - 1 ? color : `${color};${share}`,\n );\n return `style=\"striped\", fillcolor=\"${weighted.join(':')}\", class=\"${STRIPED_CLASS}\"`;\n }\n\n private statement(facts: NodeFacts, attrs: string, label: string): string {\n return ` \"${dotValue(facts.nodeId)}\" [${attrs}, label=<${label}>];\\n`;\n }\n\n /** A solid fill, the three lines on it. `extra` carries border attributes. */\n private plain(facts: NodeFacts, fill: string, fontColor: string, extra: string, style = 'filled'): string {\n return this.statement(\n facts,\n `style=\"${style}\", fillcolor=\"${fill}\", fontcolor=\"${fontColor}\"${extra}`,\n this.labelText(facts, fontColor),\n );\n }\n\n /**\n * Runtime mode. No runtime, or one runtime with no specialization: a solid fill. One runtime with a\n * specialization: NESTED. Several runtimes: full-height stripes with the text across them (a\n * specialization on such a box shows in line 3 only).\n */\n private runtime(facts: NodeFacts): string {\n const bases = this.bases(facts.frameworks);\n if (bases.length === 0) return this.plain(facts, NO_RUNTIME_COLOR, DARK_TEXT, '');\n if (bases.length > 1)\n return this.statement(\n facts,\n `${this.stripeAttrs(bases)}, fontcolor=\"${DARK_TEXT}\"`,\n this.labelText(facts, DARK_TEXT),\n );\n const base = FRAMEWORK_STYLES[bases[0]];\n const inner = this.specialization(bases[0], facts.frameworks);\n if (inner === undefined) return this.plain(facts, base.color, base.fontColor, '');\n return this.statement(\n facts,\n `style=\"filled\", fillcolor=\"${base.color}\", fontcolor=\"${inner.fontColor}\", margin=0`,\n this.nestedTable(base.color, inner, this.labelText(facts, inner.fontColor)),\n );\n }\n\n /**\n * An outer cell in the base color whose padding is the visible frame, holding an inner ROUNDED\n * table in the specialization's color that carries the text. The node's own polygon stays its\n * FIRST shape, so the hover glow and the lock outline land on the outer box only.\n */\n private nestedTable(base: string, inner: FrameworkStyle, text: string): string {\n return (\n '<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">' +\n `<TR><TD BGCOLOR=\"${base}\" CELLPADDING=\"${NEST_PAD}\">` +\n `<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"${INNER_PAD}\" BGCOLOR=\"${inner.color}\" STYLE=\"rounded\">` +\n `<TR><TD>${text}</TD></TR></TABLE></TD></TR></TABLE>`\n );\n }\n}\n"]}
|
|
@@ -16,8 +16,12 @@ declare class WpRenderBand {
|
|
|
16
16
|
declare class WpFilteredDot {
|
|
17
17
|
private readonly model;
|
|
18
18
|
constructor(model: RenderModelJson);
|
|
19
|
-
/**
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* `nodeDot` picks each box's statement — the architecture page passes its current color mode's.
|
|
21
|
+
* `keepEmptyLevels` keeps a level whose boxes were all filtered out as a thin labeled band, so
|
|
22
|
+
* every remaining box stays in its own L-row (the architecture page); otherwise it is dropped.
|
|
23
|
+
*/
|
|
24
|
+
render(retained: Set<string>, nodeDot?: (node: RenderNodeJson) => string, keepEmptyLevels?: boolean): string;
|
|
21
25
|
private bandDot;
|
|
22
26
|
}
|
|
23
27
|
/** Page-owned state survives replacements; rendering failures leave the usable SVG intact. */
|
|
@@ -38,6 +42,13 @@ declare abstract class WpFilterPage {
|
|
|
38
42
|
protected nodeDot(node: RenderNodeJson): string;
|
|
39
43
|
/** Whether an unfiltered draw may use the model's precomputed `fullDot` verbatim. */
|
|
40
44
|
protected usesFullDot(): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* The page's own filter on top of "Hide unconnected": the architecture page intersects the set
|
|
47
|
+
* with its Filter popover (changes, runtime, role). Everything, by default.
|
|
48
|
+
*/
|
|
49
|
+
protected narrow(retained: Set<string>): Set<string>;
|
|
50
|
+
/** Whether a level emptied by filtering stays as a thin labeled band (see WpFilteredDot.render). */
|
|
51
|
+
protected keepsEmptyLevels(): boolean;
|
|
41
52
|
/**
|
|
42
53
|
* Draw again with the current filter — after a color-mode switch. A control outside the graph
|
|
43
54
|
* (a drawer button) keeps keyboard focus; the redraw would otherwise move it into the graph.
|
|
@@ -54,13 +54,17 @@ class WpFilteredDot {
|
|
|
54
54
|
constructor(model) {
|
|
55
55
|
this.model = model;
|
|
56
56
|
}
|
|
57
|
-
/**
|
|
58
|
-
|
|
57
|
+
/**
|
|
58
|
+
* `nodeDot` picks each box's statement — the architecture page passes its current color mode's.
|
|
59
|
+
* `keepEmptyLevels` keeps a level whose boxes were all filtered out as a thin labeled band, so
|
|
60
|
+
* every remaining box stays in its own L-row (the architecture page); otherwise it is dropped.
|
|
61
|
+
*/
|
|
62
|
+
render(retained, nodeDot = (node) => node.dot, keepEmptyLevels = false) {
|
|
59
63
|
const nodes = this.model.nodes.filter((node) => retained.has(node.id));
|
|
60
64
|
const edges = this.model.edges.filter((edge) => retained.has(edge.from) && retained.has(edge.to));
|
|
61
65
|
const bands = this.model.bands
|
|
62
66
|
.map((band) => new WpRenderBand(band.level, band.nodeNames.filter((id) => retained.has(id))))
|
|
63
|
-
.filter((band) => band.nodeNames.length > 0);
|
|
67
|
+
.filter((band) => keepEmptyLevels || band.nodeNames.length > 0);
|
|
64
68
|
return (this.model.header +
|
|
65
69
|
nodes.map((node) => nodeDot(node)).join('') +
|
|
66
70
|
this.bandDot(bands) +
|
|
@@ -73,7 +77,12 @@ class WpFilteredDot {
|
|
|
73
77
|
let dot = '';
|
|
74
78
|
for (const band of bands) {
|
|
75
79
|
const anchor = `__wp_layout_L${band.level}`;
|
|
76
|
-
|
|
80
|
+
// The same bytes as LevelBandLayout.emptyBandAttrs (graph-level-bands.ts).
|
|
81
|
+
const attrs = band.nodeNames.length > 0
|
|
82
|
+
? nodeAttrs
|
|
83
|
+
: '[shape=plaintext, style="", width=0.01, height=0.15, margin=0, fontsize=9, fontcolor="#9a9eab", ' +
|
|
84
|
+
`label="L${band.level} · no matching projects", class="wp-layout wp-empty-level"]`;
|
|
85
|
+
dot += ` "${anchor}" ${attrs};\n { rank=same; "${anchor}"; `;
|
|
77
86
|
dot += band.nodeNames.map((id) => `${JSON.stringify(id)}; `).join('') + '}\n';
|
|
78
87
|
}
|
|
79
88
|
for (let i = 0; i + 1 < bands.length; i++) {
|
|
@@ -131,6 +140,17 @@ class WpFilterPage {
|
|
|
131
140
|
usesFullDot() {
|
|
132
141
|
return true;
|
|
133
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* The page's own filter on top of "Hide unconnected": the architecture page intersects the set
|
|
145
|
+
* with its Filter popover (changes, runtime, role). Everything, by default.
|
|
146
|
+
*/
|
|
147
|
+
narrow(retained) {
|
|
148
|
+
return retained;
|
|
149
|
+
}
|
|
150
|
+
/** Whether a level emptied by filtering stays as a thin labeled band (see WpFilteredDot.render). */
|
|
151
|
+
keepsEmptyLevels() {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
134
154
|
/**
|
|
135
155
|
* Draw again with the current filter — after a color-mode switch. A control outside the graph
|
|
136
156
|
* (a drawer button) keeps keyboard focus; the redraw would otherwise move it into the graph.
|
|
@@ -152,9 +172,9 @@ class WpFilterPage {
|
|
|
152
172
|
const host = document.getElementById('graph');
|
|
153
173
|
if (host === null)
|
|
154
174
|
return;
|
|
155
|
-
const retained = anchor === null
|
|
175
|
+
const retained = this.narrow(anchor === null
|
|
156
176
|
? new Set(this.model.nodes.map((node) => node.id))
|
|
157
|
-
: this.chain.nodes(anchor);
|
|
177
|
+
: this.chain.nodes(anchor));
|
|
158
178
|
const previousAnchor = this.anchor;
|
|
159
179
|
const previousRetained = this.retained;
|
|
160
180
|
const previousSvg = host.querySelector('svg');
|
|
@@ -164,7 +184,7 @@ class WpFilterPage {
|
|
|
164
184
|
try {
|
|
165
185
|
const dot = anchor === null && this.usesFullDot()
|
|
166
186
|
? this.model.fullDot
|
|
167
|
-
: new WpFilteredDot(this.model).render(retained, (node) => this.nodeDot(node));
|
|
187
|
+
: new WpFilteredDot(this.model).render(retained, (node) => this.nodeDot(node), this.keepsEmptyLevels());
|
|
168
188
|
const svg = this.viz.renderSVGElement(dot);
|
|
169
189
|
this.prepareSvg(svg);
|
|
170
190
|
WpNodeMenu.close();
|