@webpieces/nx-webpieces-rules 0.4.912 → 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.
Files changed (72) hide show
  1. package/README.md +11 -0
  2. package/executors.json +5 -0
  3. package/package.json +7 -7
  4. package/src/executors/help/executor.js +2 -0
  5. package/src/executors/help/executor.js.map +1 -1
  6. package/src/executors/visualize-runtime/executor.d.ts +3 -1
  7. package/src/executors/visualize-runtime/executor.js +9 -3
  8. package/src/executors/visualize-runtime/executor.js.map +1 -1
  9. package/src/executors/visualize-runtime-goal/executor.d.ts +27 -0
  10. package/src/executors/visualize-runtime-goal/executor.js +98 -0
  11. package/src/executors/visualize-runtime-goal/executor.js.map +1 -0
  12. package/src/executors/visualize-runtime-goal/schema.json +13 -0
  13. package/src/lib/graph-color-modes.d.ts +8 -1
  14. package/src/lib/graph-color-modes.js +11 -1
  15. package/src/lib/graph-color-modes.js.map +1 -1
  16. package/src/lib/graph-filter.client.d.ts +9 -2
  17. package/src/lib/graph-filter.client.js +15 -0
  18. package/src/lib/graph-filter.client.js.map +1 -1
  19. package/src/lib/graph-mode-state.client.d.ts +9 -2
  20. package/src/lib/graph-mode-state.client.js +17 -4
  21. package/src/lib/graph-mode-state.client.js.map +1 -1
  22. package/src/lib/graph-page-shell.js +6 -5
  23. package/src/lib/graph-page-shell.js.map +1 -1
  24. package/src/lib/graph-render-model.d.ts +41 -0
  25. package/src/lib/graph-render-model.js +45 -1
  26. package/src/lib/graph-render-model.js.map +1 -1
  27. package/src/lib/graph-visualizer.client.d.ts +7 -1
  28. package/src/lib/graph-visualizer.client.js +37 -4
  29. package/src/lib/graph-visualizer.client.js.map +1 -1
  30. package/src/lib/runtime-goal-comparison.d.ts +55 -0
  31. package/src/lib/runtime-goal-comparison.js +209 -0
  32. package/src/lib/runtime-goal-comparison.js.map +1 -0
  33. package/src/lib/runtime-goal-details.d.ts +17 -0
  34. package/src/lib/runtime-goal-details.js +118 -0
  35. package/src/lib/runtime-goal-details.js.map +1 -0
  36. package/src/lib/runtime-goal-file.d.ts +72 -0
  37. package/src/lib/runtime-goal-file.js +201 -0
  38. package/src/lib/runtime-goal-file.js.map +1 -0
  39. package/src/lib/runtime-goal-styles.d.ts +10 -0
  40. package/src/lib/runtime-goal-styles.js +25 -0
  41. package/src/lib/runtime-goal-styles.js.map +1 -0
  42. package/src/lib/runtime-goal-validator.d.ts +39 -0
  43. package/src/lib/runtime-goal-validator.js +236 -0
  44. package/src/lib/runtime-goal-validator.js.map +1 -0
  45. package/src/lib/runtime-goal-view.d.ts +22 -0
  46. package/src/lib/runtime-goal-view.js +64 -0
  47. package/src/lib/runtime-goal-view.js.map +1 -0
  48. package/src/lib/runtime-graph-diff.d.ts +107 -0
  49. package/src/lib/runtime-graph-diff.js +346 -0
  50. package/src/lib/runtime-graph-diff.js.map +1 -0
  51. package/src/lib/runtime-html-page.d.ts +2 -0
  52. package/src/lib/runtime-html-page.js +28 -3
  53. package/src/lib/runtime-html-page.js.map +1 -1
  54. package/src/lib/runtime-layout.d.ts +2 -0
  55. package/src/lib/runtime-layout.js +4 -0
  56. package/src/lib/runtime-layout.js.map +1 -1
  57. package/src/lib/runtime-union-graph.d.ts +20 -0
  58. package/src/lib/runtime-union-graph.js +94 -0
  59. package/src/lib/runtime-union-graph.js.map +1 -0
  60. package/src/lib/runtime-visualizer.client.js +7 -3
  61. package/src/lib/runtime-visualizer.client.js.map +1 -1
  62. package/src/lib/runtime-visualizer.d.ts +8 -3
  63. package/src/lib/runtime-visualizer.js +18 -10
  64. package/src/lib/runtime-visualizer.js.map +1 -1
  65. package/src/lib/runtime-viz-options.d.ts +28 -1
  66. package/src/lib/runtime-viz-options.js +36 -2
  67. package/src/lib/runtime-viz-options.js.map +1 -1
  68. package/src/plugin.js +2 -2
  69. package/src/plugin.js.map +1 -1
  70. package/src/runtime-targets.d.ts +6 -0
  71. package/src/runtime-targets.js +17 -0
  72. package/src/runtime-targets.js.map +1 -1
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RuntimeComparisonInputs = void 0;
4
+ const rules_config_1 = require("@webpieces/rules-config");
5
+ const runtime_graph_io_1 = require("./runtime-graph-io");
6
+ const saved_snapshot_1 = require("./saved-snapshot");
7
+ const runtime_goal_file_1 = require("./runtime-goal-file");
8
+ const graph_render_model_1 = require("./graph-render-model");
9
+ const runtime_goal_comparison_1 = require("./runtime-goal-comparison");
10
+ const toError_1 = require("../toError");
11
+ /**
12
+ * Loads either saved runtime file for the OTHER page's comparison, turning a missing or unusable file
13
+ * into the reason Goal vs Current is unavailable — never into "no differences".
14
+ */
15
+ class RuntimeComparisonInputs {
16
+ snapshot;
17
+ goalFile;
18
+ constructor(snapshot = new saved_snapshot_1.SavedSnapshot(), goalFile = new runtime_goal_file_1.RuntimeGoalFile()) {
19
+ this.snapshot = snapshot;
20
+ this.goalFile = goalFile;
21
+ }
22
+ /** The saved current graph, or why it cannot be compared. */
23
+ current(workspaceRoot) {
24
+ // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- an unusable comparison input becomes the mode's stated reason; the page itself still renders
25
+ try {
26
+ return this.snapshot.loadRuntime(workspaceRoot);
27
+ }
28
+ catch (err) {
29
+ const error = (0, toError_1.toError)(err);
30
+ return `No usable saved current runtime graph at ${runtime_graph_io_1.DEFAULT_RUNTIME_GRAPH_PATH}: ${this.text(error)}`;
31
+ }
32
+ }
33
+ /** The saved goal, or why it cannot be compared (missing: how to start one). */
34
+ goal(workspaceRoot) {
35
+ if (!this.goalFile.exists(workspaceRoot))
36
+ return `No runtime goal at ${runtime_goal_file_1.DEFAULT_RUNTIME_GOAL_PATH}. Start a proposal with: ${runtime_goal_file_1.RUNTIME_GOAL_INIT_COMMAND}`;
37
+ // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- an unusable comparison input becomes the mode's stated reason; the page itself still renders
38
+ try {
39
+ return this.goalFile.load(workspaceRoot);
40
+ }
41
+ catch (err) {
42
+ const error = (0, toError_1.toError)(err);
43
+ return this.text(error);
44
+ }
45
+ }
46
+ view(current, goal, options) {
47
+ if (typeof current === 'string')
48
+ return this.unavailable(current);
49
+ if (typeof goal === 'string')
50
+ return this.unavailable(goal);
51
+ return new runtime_goal_comparison_1.RuntimeGoalComparison().build(current, goal, options);
52
+ }
53
+ /** Goal vs Current with no overlay: the mode is disabled and says `reason` instead. */
54
+ unavailable(reason) {
55
+ return new graph_render_model_1.RuntimeComparisonView(false, reason, 'Current → Goal', '', null, {}, {}, []);
56
+ }
57
+ text(error) {
58
+ if (error instanceof rules_config_1.RuleFailError)
59
+ return (0, rules_config_1.renderRuleFailForHuman)(error);
60
+ throw error;
61
+ }
62
+ }
63
+ exports.RuntimeComparisonInputs = RuntimeComparisonInputs;
64
+ //# sourceMappingURL=runtime-goal-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-goal-view.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-goal-view.ts"],"names":[],"mappings":";;;AAAA,0DAAgF;AAEhF,yDAAgE;AAChE,qDAAiD;AACjD,2DAA4G;AAC5G,6DAA6D;AAC7D,uEAAkE;AAElE,wCAAqC;AAErC;;;GAGG;AACH,MAAa,uBAAuB;IAEX;IACA;IAFrB,YACqB,WAA0B,IAAI,8BAAa,EAAE,EAC7C,WAA4B,IAAI,mCAAe,EAAE;QADjD,aAAQ,GAAR,QAAQ,CAAqC;QAC7C,aAAQ,GAAR,QAAQ,CAAyC;IACnE,CAAC;IAEJ,6DAA6D;IAC7D,OAAO,CAAC,aAAqB;QACzB,8JAA8J;QAC9J,IAAI,CAAC;YACD,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,iBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,OAAO,4CAA4C,6CAA0B,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzG,CAAC;IACL,CAAC;IAED,gFAAgF;IAChF,IAAI,CAAC,aAAqB;QACtB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC;YACpC,OAAO,sBAAsB,6CAAyB,4BAA4B,6CAAyB,EAAE,CAAC;QAClH,8JAA8J;QAC9J,IAAI,CAAC;YACD,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,iBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACL,CAAC;IAED,IAAI,CAAC,OAA8B,EAAE,IAA2B,EAAE,OAA0B;QACxF,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAClE,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC5D,OAAO,IAAI,+CAAqB,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACrE,CAAC;IAED,uFAAuF;IACvF,WAAW,CAAC,MAAc;QACtB,OAAO,IAAI,0CAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5F,CAAC;IAEO,IAAI,CAAC,KAAY;QACrB,IAAI,KAAK,YAAY,4BAAa;YAAE,OAAO,IAAA,qCAAsB,EAAC,KAAK,CAAC,CAAC;QACzE,MAAM,KAAK,CAAC;IAChB,CAAC;CACJ;AA7CD,0DA6CC","sourcesContent":["import { RuleFailError, renderRuleFailForHuman } from '@webpieces/rules-config';\nimport type { RuntimeGraph } from './runtime-graph-model';\nimport { DEFAULT_RUNTIME_GRAPH_PATH } from './runtime-graph-io';\nimport { SavedSnapshot } from './saved-snapshot';\nimport { DEFAULT_RUNTIME_GOAL_PATH, RUNTIME_GOAL_INIT_COMMAND, RuntimeGoalFile } from './runtime-goal-file';\nimport { RuntimeComparisonView } from './graph-render-model';\nimport { RuntimeGoalComparison } from './runtime-goal-comparison';\nimport type { RuntimeVizOptions } from './runtime-viz-options';\nimport { toError } from '../toError';\n\n/**\n * Loads either saved runtime file for the OTHER page's comparison, turning a missing or unusable file\n * into the reason Goal vs Current is unavailable — never into \"no differences\".\n */\nexport class RuntimeComparisonInputs {\n constructor(\n private readonly snapshot: SavedSnapshot = new SavedSnapshot(),\n private readonly goalFile: RuntimeGoalFile = new RuntimeGoalFile(),\n ) {}\n\n /** The saved current graph, or why it cannot be compared. */\n current(workspaceRoot: string): RuntimeGraph | string {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- an unusable comparison input becomes the mode's stated reason; the page itself still renders\n try {\n return this.snapshot.loadRuntime(workspaceRoot);\n } catch (err: unknown) {\n const error = toError(err);\n return `No usable saved current runtime graph at ${DEFAULT_RUNTIME_GRAPH_PATH}: ${this.text(error)}`;\n }\n }\n\n /** The saved goal, or why it cannot be compared (missing: how to start one). */\n goal(workspaceRoot: string): RuntimeGraph | string {\n if (!this.goalFile.exists(workspaceRoot))\n return `No runtime goal at ${DEFAULT_RUNTIME_GOAL_PATH}. Start a proposal with: ${RUNTIME_GOAL_INIT_COMMAND}`;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- an unusable comparison input becomes the mode's stated reason; the page itself still renders\n try {\n return this.goalFile.load(workspaceRoot);\n } catch (err: unknown) {\n const error = toError(err);\n return this.text(error);\n }\n }\n\n view(current: RuntimeGraph | string, goal: RuntimeGraph | string, options: RuntimeVizOptions): RuntimeComparisonView {\n if (typeof current === 'string') return this.unavailable(current);\n if (typeof goal === 'string') return this.unavailable(goal);\n return new RuntimeGoalComparison().build(current, goal, options);\n }\n\n /** Goal vs Current with no overlay: the mode is disabled and says `reason` instead. */\n unavailable(reason: string): RuntimeComparisonView {\n return new RuntimeComparisonView(false, reason, 'Current → Goal', '', null, {}, {}, []);\n }\n\n private text(error: Error): string {\n if (error instanceof RuleFailError) return renderRuleFailForHuman(error);\n throw error;\n }\n}\n"]}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Goal vs Current (#1239): a SEMANTIC diff of two saved RuntimeGraph files.
3
+ *
4
+ * Both graphs are flattened into FACTS keyed by stable underlying identities — a service's project
5
+ * key, a queue's `Api.method`, a contract queue's API, an external system's identity — never by a
6
+ * shortened display name or a renderer-generated edge id. A fact is a NODE (service, queue, contract
7
+ * queue, external system, remote service, external library, trigger), a RELATIONSHIP (rpc call,
8
+ * enqueue, delivery, external use, remote call, unresolved use) or a CONTRACT (an `apis` entry).
9
+ *
10
+ * Comparison policy:
11
+ * - Values are canonical strings. Set-like arrays are de-duplicated and sorted, so object key order
12
+ * and array order alone never produce a change.
13
+ * - Queue facts are compared per method / per contract BEFORE presentation grouping, and every
14
+ * pubsub edge is split into its enqueue and delivery relationships, so a merged queue box cannot
15
+ * hide a difference between its members.
16
+ * - Bookkeeping is ignored: `levelBecause` (explanatory text the level machinery regenerates),
17
+ * `wiringUses` / `wiringImplements` (reviewed provenance), and `dependsOn` (the BUILD graph, which
18
+ * this runtime comparison deliberately does not cover). `maxLevel` is reported in the summary.
19
+ * - A service's outgoing relationships are one of its properties, so a service whose calls changed
20
+ * is itself CHANGED and its details show the before/after call list.
21
+ */
22
+ import type { RuntimeEdge, RuntimeGraph } from './runtime-graph-model';
23
+ export declare enum RuntimeDiffStatus {
24
+ ADDED = "added",
25
+ REMOVED = "removed",
26
+ CHANGED = "changed",
27
+ UNCHANGED = "unchanged"
28
+ }
29
+ export declare enum RuntimeFactKind {
30
+ NODE = "node",
31
+ RELATIONSHIP = "relationship",
32
+ CONTRACT = "contract"
33
+ }
34
+ /** One identity's canonical properties in one graph. */
35
+ export declare class RuntimeFact {
36
+ readonly id: string;
37
+ readonly kind: RuntimeFactKind;
38
+ readonly category: string;
39
+ readonly label: string;
40
+ readonly properties: Record<string, string>;
41
+ constructor(id: string, kind: RuntimeFactKind, category: string, label: string, properties: Record<string, string>);
42
+ }
43
+ /** One identity compared across Current → Goal. `before` is null when added, `after` when removed. */
44
+ export declare class RuntimeFactChange {
45
+ readonly id: string;
46
+ readonly kind: RuntimeFactKind;
47
+ readonly category: string;
48
+ readonly label: string;
49
+ readonly status: RuntimeDiffStatus;
50
+ readonly before: Record<string, string> | null;
51
+ readonly after: Record<string, string> | null;
52
+ readonly changedFields: string[];
53
+ constructor(id: string, kind: RuntimeFactKind, category: string, label: string, status: RuntimeDiffStatus, before: Record<string, string> | null, after: Record<string, string> | null, changedFields: string[]);
54
+ /** Human lines for a details panel: the status, then `field: before → after` per changed field. */
55
+ lines(): string[];
56
+ private listing;
57
+ }
58
+ export declare class RuntimeDiffCounts {
59
+ readonly added: number;
60
+ readonly removed: number;
61
+ readonly changed: number;
62
+ readonly unchanged: number;
63
+ constructor(added: number, removed: number, changed: number, unchanged: number);
64
+ }
65
+ /** Every compared identity, sorted by id, plus graph-level bookkeeping. */
66
+ export declare class RuntimeGraphDiffResult {
67
+ readonly changes: RuntimeFactChange[];
68
+ readonly maxLevelBefore: number;
69
+ readonly maxLevelAfter: number;
70
+ private readonly byId;
71
+ constructor(changes: RuntimeFactChange[], maxLevelBefore: number, maxLevelAfter: number);
72
+ get(id: string): RuntimeFactChange | undefined;
73
+ counts(): RuntimeDiffCounts;
74
+ identical(): boolean;
75
+ /** The changed identities only (added, removed, changed), in id order. */
76
+ differences(): RuntimeFactChange[];
77
+ }
78
+ /** Flattens one RuntimeGraph into its facts. */
79
+ export declare class RuntimeFactSet {
80
+ private readonly graph;
81
+ readonly facts: Map<string, RuntimeFact>;
82
+ constructor(graph: RuntimeGraph);
83
+ private add;
84
+ private relationships;
85
+ /** `queue:Api.method` for a method-level hop; one `contract-queue:Api` per contract otherwise. */
86
+ queueIds(edge: RuntimeEdge): string[];
87
+ private services;
88
+ private queues;
89
+ private externals;
90
+ private remotes;
91
+ private triggers;
92
+ private contracts;
93
+ private owner;
94
+ private node;
95
+ private relation;
96
+ /** Set semantics: de-duplicated and sorted, so order alone is never a change. */
97
+ private set;
98
+ private split;
99
+ private value;
100
+ /** JSON with sorted keys, for the two map-or-string fields. */
101
+ private canonical;
102
+ }
103
+ /** Compares two saved runtime graphs, Current → Goal. Pure; deterministic for equivalent inputs. */
104
+ export declare class RuntimeGraphDiff {
105
+ compare(current: RuntimeGraph, goal: RuntimeGraph): RuntimeGraphDiffResult;
106
+ private change;
107
+ }
@@ -0,0 +1,346 @@
1
+ "use strict";
2
+ /**
3
+ * Goal vs Current (#1239): a SEMANTIC diff of two saved RuntimeGraph files.
4
+ *
5
+ * Both graphs are flattened into FACTS keyed by stable underlying identities — a service's project
6
+ * key, a queue's `Api.method`, a contract queue's API, an external system's identity — never by a
7
+ * shortened display name or a renderer-generated edge id. A fact is a NODE (service, queue, contract
8
+ * queue, external system, remote service, external library, trigger), a RELATIONSHIP (rpc call,
9
+ * enqueue, delivery, external use, remote call, unresolved use) or a CONTRACT (an `apis` entry).
10
+ *
11
+ * Comparison policy:
12
+ * - Values are canonical strings. Set-like arrays are de-duplicated and sorted, so object key order
13
+ * and array order alone never produce a change.
14
+ * - Queue facts are compared per method / per contract BEFORE presentation grouping, and every
15
+ * pubsub edge is split into its enqueue and delivery relationships, so a merged queue box cannot
16
+ * hide a difference between its members.
17
+ * - Bookkeeping is ignored: `levelBecause` (explanatory text the level machinery regenerates),
18
+ * `wiringUses` / `wiringImplements` (reviewed provenance), and `dependsOn` (the BUILD graph, which
19
+ * this runtime comparison deliberately does not cover). `maxLevel` is reported in the summary.
20
+ * - A service's outgoing relationships are one of its properties, so a service whose calls changed
21
+ * is itself CHANGED and its details show the before/after call list.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.RuntimeGraphDiff = exports.RuntimeFactSet = exports.RuntimeGraphDiffResult = exports.RuntimeDiffCounts = exports.RuntimeFactChange = exports.RuntimeFact = exports.RuntimeFactKind = exports.RuntimeDiffStatus = void 0;
25
+ var RuntimeDiffStatus;
26
+ (function (RuntimeDiffStatus) {
27
+ RuntimeDiffStatus["ADDED"] = "added";
28
+ RuntimeDiffStatus["REMOVED"] = "removed";
29
+ RuntimeDiffStatus["CHANGED"] = "changed";
30
+ RuntimeDiffStatus["UNCHANGED"] = "unchanged";
31
+ })(RuntimeDiffStatus || (exports.RuntimeDiffStatus = RuntimeDiffStatus = {}));
32
+ var RuntimeFactKind;
33
+ (function (RuntimeFactKind) {
34
+ RuntimeFactKind["NODE"] = "node";
35
+ RuntimeFactKind["RELATIONSHIP"] = "relationship";
36
+ RuntimeFactKind["CONTRACT"] = "contract";
37
+ })(RuntimeFactKind || (exports.RuntimeFactKind = RuntimeFactKind = {}));
38
+ /** One identity's canonical properties in one graph. */
39
+ class RuntimeFact {
40
+ id;
41
+ kind;
42
+ category;
43
+ label;
44
+ properties;
45
+ constructor(id, kind, category, label, properties) {
46
+ this.id = id;
47
+ this.kind = kind;
48
+ this.category = category;
49
+ this.label = label;
50
+ this.properties = properties;
51
+ }
52
+ }
53
+ exports.RuntimeFact = RuntimeFact;
54
+ /** One identity compared across Current → Goal. `before` is null when added, `after` when removed. */
55
+ class RuntimeFactChange {
56
+ id;
57
+ kind;
58
+ category;
59
+ label;
60
+ status;
61
+ before;
62
+ after;
63
+ changedFields;
64
+ constructor(id, kind, category, label, status, before, after, changedFields) {
65
+ this.id = id;
66
+ this.kind = kind;
67
+ this.category = category;
68
+ this.label = label;
69
+ this.status = status;
70
+ this.before = before;
71
+ this.after = after;
72
+ this.changedFields = changedFields;
73
+ }
74
+ /** Human lines for a details panel: the status, then `field: before → after` per changed field. */
75
+ lines() {
76
+ const head = `${this.label} — ${this.status}`;
77
+ if (this.status === RuntimeDiffStatus.ADDED)
78
+ return [head, ...this.listing(this.after)];
79
+ if (this.status === RuntimeDiffStatus.REMOVED)
80
+ return [head, ...this.listing(this.before)];
81
+ if (this.status === RuntimeDiffStatus.UNCHANGED)
82
+ return [head];
83
+ return [head, ...this.changedFields.map((field) => ` ${field}: ${this.before[field] ?? '(absent)'} → ${this.after[field] ?? '(absent)'}`)];
84
+ }
85
+ listing(properties) {
86
+ return Object.keys(properties).map((field) => ` ${field}: ${properties[field]}`);
87
+ }
88
+ }
89
+ exports.RuntimeFactChange = RuntimeFactChange;
90
+ class RuntimeDiffCounts {
91
+ added;
92
+ removed;
93
+ changed;
94
+ unchanged;
95
+ constructor(added, removed, changed, unchanged) {
96
+ this.added = added;
97
+ this.removed = removed;
98
+ this.changed = changed;
99
+ this.unchanged = unchanged;
100
+ }
101
+ }
102
+ exports.RuntimeDiffCounts = RuntimeDiffCounts;
103
+ /** Every compared identity, sorted by id, plus graph-level bookkeeping. */
104
+ class RuntimeGraphDiffResult {
105
+ changes;
106
+ maxLevelBefore;
107
+ maxLevelAfter;
108
+ byId = new Map();
109
+ constructor(changes, maxLevelBefore, maxLevelAfter) {
110
+ this.changes = changes;
111
+ this.maxLevelBefore = maxLevelBefore;
112
+ this.maxLevelAfter = maxLevelAfter;
113
+ for (const change of changes)
114
+ this.byId.set(change.id, change);
115
+ }
116
+ get(id) {
117
+ return this.byId.get(id);
118
+ }
119
+ counts() {
120
+ const count = (status) => this.changes.filter((change) => change.status === status).length;
121
+ return new RuntimeDiffCounts(count(RuntimeDiffStatus.ADDED), count(RuntimeDiffStatus.REMOVED), count(RuntimeDiffStatus.CHANGED), count(RuntimeDiffStatus.UNCHANGED));
122
+ }
123
+ identical() {
124
+ return this.changes.every((change) => change.status === RuntimeDiffStatus.UNCHANGED);
125
+ }
126
+ /** The changed identities only (added, removed, changed), in id order. */
127
+ differences() {
128
+ return this.changes.filter((change) => change.status !== RuntimeDiffStatus.UNCHANGED);
129
+ }
130
+ }
131
+ exports.RuntimeGraphDiffResult = RuntimeGraphDiffResult;
132
+ /** One vendor library's unresolved uses, gathered before they become a fact. */
133
+ class ExternalLibraryFacts {
134
+ level;
135
+ apis = [];
136
+ usedBy = [];
137
+ constructor(level) {
138
+ this.level = level;
139
+ }
140
+ }
141
+ /** Flattens one RuntimeGraph into its facts. */
142
+ class RuntimeFactSet {
143
+ graph;
144
+ facts = new Map();
145
+ constructor(graph) {
146
+ this.graph = graph;
147
+ this.relationships();
148
+ this.services();
149
+ this.queues();
150
+ this.externals();
151
+ this.remotes();
152
+ this.triggers();
153
+ this.contracts();
154
+ }
155
+ add(fact) {
156
+ const existing = this.facts.get(fact.id);
157
+ if (existing === undefined) {
158
+ this.facts.set(fact.id, fact);
159
+ return;
160
+ }
161
+ // Duplicate relationship facts (two rpc edges between one pair) fold into one, union of values.
162
+ const merged = { ...existing.properties };
163
+ for (const [key, value] of Object.entries(fact.properties))
164
+ merged[key] = this.set([...this.split(merged[key]), ...this.split(value)]);
165
+ this.facts.set(fact.id, new RuntimeFact(fact.id, fact.kind, fact.category, fact.label, merged));
166
+ }
167
+ relationships() {
168
+ for (const edge of this.graph.runtimeEdges) {
169
+ if (edge.type !== 'pubsub') {
170
+ const props = { via: this.set(edge.via) };
171
+ if (edge.cutLegacyCycle === true)
172
+ props['cutLegacyCycle'] = 'true';
173
+ this.add(this.relation(`rpc:${edge.from}->${edge.to}`, 'rpc call', `RPC ${edge.from} → ${edge.to}`, props));
174
+ continue;
175
+ }
176
+ for (const queue of this.queueIds(edge)) {
177
+ this.add(this.relation(`enqueue:${edge.from}->${queue}`, 'enqueue', `Enqueue ${edge.from} → ${queue}`, {}));
178
+ this.add(this.relation(`deliver:${queue}->${edge.to}`, 'delivery', `Deliver ${queue} → ${edge.to}`, {}));
179
+ }
180
+ }
181
+ for (const [id, system] of Object.entries(this.graph.externalSystems ?? {})) {
182
+ for (const user of system.usedBy)
183
+ this.add(this.relation(`external-use:${user}->external-system:${id}`, 'external use', `Uses ${user} → ${system.label}`, {}));
184
+ }
185
+ for (const [name, remote] of Object.entries(this.graph.remoteServices ?? {})) {
186
+ for (const call of remote.calledBy)
187
+ this.add(this.relation(`remote-call:${call.from}->remote-service:${name}#${call.type}`, 'remote call', `Remote ${call.type} ${call.from} → ${name}`, { via: this.set(call.via) }));
188
+ }
189
+ for (const use of this.graph.unresolvedUses) {
190
+ const owner = this.owner(use.api);
191
+ this.add(this.relation(`unresolved-use:${use.service}->${use.api}`, 'unresolved use', `Uses ${use.service} → ${owner}#${use.api}`, { owner }));
192
+ }
193
+ }
194
+ /** `queue:Api.method` for a method-level hop; one `contract-queue:Api` per contract otherwise. */
195
+ queueIds(edge) {
196
+ return edge.queue === undefined ? edge.via.map((api) => `contract-queue:${api}`) : [`queue:${edge.queue}`];
197
+ }
198
+ services() {
199
+ const outgoing = new Map();
200
+ for (const fact of this.facts.values()) {
201
+ const from = fact.id.slice(fact.id.indexOf(':') + 1).split('->')[0];
202
+ if (this.graph.services[from] === undefined || fact.id.startsWith('deliver:'))
203
+ continue;
204
+ if (!outgoing.has(from))
205
+ outgoing.set(from, []);
206
+ outgoing.get(from).push(fact.id.slice(fact.id.indexOf('->') + 2) + (fact.properties['via'] === undefined ? '' : ` [${fact.properties['via']}]`));
207
+ }
208
+ for (const [name, service] of Object.entries(this.graph.services)) {
209
+ this.add(new RuntimeFact(`service:${name}`, RuntimeFactKind.NODE, 'service', `Service ${name}`, {
210
+ level: `L${service.level}`,
211
+ role: this.value(service.role),
212
+ serviceName: this.value(service.serviceName),
213
+ callsService: this.value(service.callsService === undefined ? undefined : this.canonical(service.callsService)),
214
+ implements: this.set(service.implements),
215
+ implementsVia: this.value(service.implementsVia === undefined ? undefined : this.canonical(service.implementsVia)),
216
+ products: this.set(service.products ?? []),
217
+ drawOnGraph: String(service.drawOnGraph !== false),
218
+ outgoing: this.set(outgoing.get(name) ?? []),
219
+ }));
220
+ }
221
+ }
222
+ queues() {
223
+ const flow = (queue) => ({
224
+ level: `L${queue.level}`,
225
+ selfQueue: String(queue.selfQueue),
226
+ producedBy: this.set(queue.producedBy),
227
+ consumedBy: this.set(queue.consumedBy),
228
+ });
229
+ for (const [key, queue] of Object.entries(this.graph.queues)) {
230
+ this.add(this.node(`queue:${key}`, 'queue', `Queue ${key}`, { ...flow(queue), queueName: queue.queueName }));
231
+ }
232
+ for (const [api, queue] of Object.entries(this.graph.contractQueues)) {
233
+ this.add(this.node(`contract-queue:${api}`, 'contract queue', `Contract queue ${api}`, flow(queue)));
234
+ }
235
+ }
236
+ externals() {
237
+ for (const [id, system] of Object.entries(this.graph.externalSystems ?? {})) {
238
+ this.add(this.node(`external-system:${id}`, 'external system', `External ${system.label}`, {
239
+ level: `L${system.level}`,
240
+ kind: system.kind,
241
+ label: system.label,
242
+ usedBy: this.set(system.usedBy),
243
+ apis: this.set(system.apis),
244
+ }));
245
+ }
246
+ const libraries = new Map();
247
+ for (const use of this.graph.unresolvedUses) {
248
+ if (this.graph.apis[use.api]?.externalSystem !== undefined)
249
+ continue;
250
+ const owner = this.owner(use.api);
251
+ if (!libraries.has(owner))
252
+ libraries.set(owner, new ExternalLibraryFacts(`L${use.level}`));
253
+ libraries.get(owner).apis.push(use.api);
254
+ libraries.get(owner).usedBy.push(use.service);
255
+ }
256
+ for (const owner of libraries.keys()) {
257
+ const facts = libraries.get(owner);
258
+ this.add(this.node(`external-library:${owner}`, 'external library', `External ${owner}`, {
259
+ level: facts.level,
260
+ apis: this.set(facts.apis),
261
+ usedBy: this.set(facts.usedBy),
262
+ }));
263
+ }
264
+ }
265
+ remotes() {
266
+ for (const [name, remote] of Object.entries(this.graph.remoteServices ?? {})) {
267
+ this.add(this.node(`remote-service:${name}`, 'remote service', `Remote service ${name}`, {
268
+ level: `L${remote.level}`,
269
+ label: this.value(remote.label),
270
+ implements: this.set(remote.implements),
271
+ }));
272
+ }
273
+ }
274
+ triggers() {
275
+ for (const trigger of this.graph.triggers) {
276
+ const caller = trigger.caller === undefined ? undefined : `${trigger.caller.kind} ${trigger.caller.label}`;
277
+ this.add(this.node(`trigger:${trigger.kind}:${trigger.api}.${trigger.method}@${trigger.service}`, `${trigger.kind} trigger`, `${trigger.kind === 'cron' ? 'Cron' : 'External'} ${trigger.api}.${trigger.method} → ${trigger.service}`, {
278
+ level: `L${trigger.level}`,
279
+ queueName: this.value(trigger.queueName),
280
+ caller: this.value(caller),
281
+ }));
282
+ }
283
+ }
284
+ contracts() {
285
+ for (const [name, api] of Object.entries(this.graph.apis)) {
286
+ this.add(new RuntimeFact(`api:${name}`, RuntimeFactKind.CONTRACT, 'contract', `Contract ${name}`, {
287
+ implementedBy: this.set(api.implementedBy),
288
+ usedBy: this.set(api.usedBy),
289
+ type: this.value(api.type),
290
+ owner: this.value(api.owner),
291
+ externalSystem: this.value(api.externalSystem === undefined ? undefined : `${api.externalSystem.kind} ${api.externalSystem.label ?? ''}`.trim()),
292
+ }));
293
+ }
294
+ }
295
+ owner(api) {
296
+ return this.graph.apis[api]?.owner ?? api;
297
+ }
298
+ node(id, category, label, properties) {
299
+ return new RuntimeFact(id, RuntimeFactKind.NODE, category, label, properties);
300
+ }
301
+ relation(id, category, label, properties) {
302
+ return new RuntimeFact(id, RuntimeFactKind.RELATIONSHIP, category, label, properties);
303
+ }
304
+ /** Set semantics: de-duplicated and sorted, so order alone is never a change. */
305
+ set(values) {
306
+ const unique = [...new Set(values)].sort();
307
+ return unique.length === 0 ? '(none)' : unique.join(', ');
308
+ }
309
+ split(value) {
310
+ return value === undefined || value === '(none)' ? [] : value.split(', ');
311
+ }
312
+ value(value) {
313
+ return value ?? '(absent)';
314
+ }
315
+ /** JSON with sorted keys, for the two map-or-string fields. */
316
+ canonical(value) {
317
+ if (typeof value === 'string')
318
+ return value;
319
+ return JSON.stringify(Object.keys(value).sort().map((key) => [key, value[key]]));
320
+ }
321
+ }
322
+ exports.RuntimeFactSet = RuntimeFactSet;
323
+ /** Compares two saved runtime graphs, Current → Goal. Pure; deterministic for equivalent inputs. */
324
+ class RuntimeGraphDiff {
325
+ compare(current, goal) {
326
+ const before = new RuntimeFactSet(current).facts;
327
+ const after = new RuntimeFactSet(goal).facts;
328
+ const ids = [...new Set([...before.keys(), ...after.keys()])].sort();
329
+ const changes = ids.map((id) => this.change(id, before.get(id), after.get(id)));
330
+ return new RuntimeGraphDiffResult(changes, current.maxLevel, goal.maxLevel);
331
+ }
332
+ change(id, before, after) {
333
+ const fact = (after ?? before);
334
+ if (before === undefined)
335
+ return new RuntimeFactChange(id, fact.kind, fact.category, fact.label, RuntimeDiffStatus.ADDED, null, after.properties, []);
336
+ if (after === undefined)
337
+ return new RuntimeFactChange(id, fact.kind, fact.category, fact.label, RuntimeDiffStatus.REMOVED, before.properties, null, []);
338
+ const fields = [...new Set([...Object.keys(before.properties), ...Object.keys(after.properties)])]
339
+ .sort()
340
+ .filter((field) => before.properties[field] !== after.properties[field]);
341
+ const status = fields.length === 0 ? RuntimeDiffStatus.UNCHANGED : RuntimeDiffStatus.CHANGED;
342
+ return new RuntimeFactChange(id, fact.kind, fact.category, fact.label, status, before.properties, after.properties, fields);
343
+ }
344
+ }
345
+ exports.RuntimeGraphDiff = RuntimeGraphDiff;
346
+ //# sourceMappingURL=runtime-graph-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-graph-diff.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-graph-diff.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Goal vs Current (#1239): a SEMANTIC diff of two saved RuntimeGraph files.\n *\n * Both graphs are flattened into FACTS keyed by stable underlying identities — a service's project\n * key, a queue's `Api.method`, a contract queue's API, an external system's identity — never by a\n * shortened display name or a renderer-generated edge id. A fact is a NODE (service, queue, contract\n * queue, external system, remote service, external library, trigger), a RELATIONSHIP (rpc call,\n * enqueue, delivery, external use, remote call, unresolved use) or a CONTRACT (an `apis` entry).\n *\n * Comparison policy:\n * - Values are canonical strings. Set-like arrays are de-duplicated and sorted, so object key order\n * and array order alone never produce a change.\n * - Queue facts are compared per method / per contract BEFORE presentation grouping, and every\n * pubsub edge is split into its enqueue and delivery relationships, so a merged queue box cannot\n * hide a difference between its members.\n * - Bookkeeping is ignored: `levelBecause` (explanatory text the level machinery regenerates),\n * `wiringUses` / `wiringImplements` (reviewed provenance), and `dependsOn` (the BUILD graph, which\n * this runtime comparison deliberately does not cover). `maxLevel` is reported in the summary.\n * - A service's outgoing relationships are one of its properties, so a service whose calls changed\n * is itself CHANGED and its details show the before/after call list.\n */\n\nimport type { RuntimeEdge, RuntimeGraph, RuntimeQueueFlow } from './runtime-graph-model';\n\nexport enum RuntimeDiffStatus {\n ADDED = 'added',\n REMOVED = 'removed',\n CHANGED = 'changed',\n UNCHANGED = 'unchanged',\n}\n\nexport enum RuntimeFactKind {\n NODE = 'node',\n RELATIONSHIP = 'relationship',\n CONTRACT = 'contract',\n}\n\n/** One identity's canonical properties in one graph. */\nexport class RuntimeFact {\n constructor(\n public readonly id: string,\n public readonly kind: RuntimeFactKind,\n public readonly category: string,\n public readonly label: string,\n public readonly properties: Record<string, string>,\n ) {}\n}\n\n/** One identity compared across Current → Goal. `before` is null when added, `after` when removed. */\nexport class RuntimeFactChange {\n constructor(\n public readonly id: string,\n public readonly kind: RuntimeFactKind,\n public readonly category: string,\n public readonly label: string,\n public readonly status: RuntimeDiffStatus,\n public readonly before: Record<string, string> | null,\n public readonly after: Record<string, string> | null,\n public readonly changedFields: string[],\n ) {}\n\n /** Human lines for a details panel: the status, then `field: before → after` per changed field. */\n lines(): string[] {\n const head = `${this.label} — ${this.status}`;\n if (this.status === RuntimeDiffStatus.ADDED) return [head, ...this.listing(this.after!)];\n if (this.status === RuntimeDiffStatus.REMOVED) return [head, ...this.listing(this.before!)];\n if (this.status === RuntimeDiffStatus.UNCHANGED) return [head];\n return [head, ...this.changedFields.map((field: string) => ` ${field}: ${this.before![field] ?? '(absent)'} → ${this.after![field] ?? '(absent)'}`)];\n }\n\n private listing(properties: Record<string, string>): string[] {\n return Object.keys(properties).map((field: string) => ` ${field}: ${properties[field]}`);\n }\n}\n\nexport class RuntimeDiffCounts {\n constructor(\n public readonly added: number,\n public readonly removed: number,\n public readonly changed: number,\n public readonly unchanged: number,\n ) {}\n}\n\n/** Every compared identity, sorted by id, plus graph-level bookkeeping. */\nexport class RuntimeGraphDiffResult {\n private readonly byId = new Map<string, RuntimeFactChange>();\n\n constructor(\n public readonly changes: RuntimeFactChange[],\n public readonly maxLevelBefore: number,\n public readonly maxLevelAfter: number,\n ) {\n for (const change of changes) this.byId.set(change.id, change);\n }\n\n get(id: string): RuntimeFactChange | undefined {\n return this.byId.get(id);\n }\n\n counts(): RuntimeDiffCounts {\n const count = (status: RuntimeDiffStatus): number => this.changes.filter((change: RuntimeFactChange) => change.status === status).length;\n return new RuntimeDiffCounts(\n count(RuntimeDiffStatus.ADDED),\n count(RuntimeDiffStatus.REMOVED),\n count(RuntimeDiffStatus.CHANGED),\n count(RuntimeDiffStatus.UNCHANGED),\n );\n }\n\n identical(): boolean {\n return this.changes.every((change: RuntimeFactChange) => change.status === RuntimeDiffStatus.UNCHANGED);\n }\n\n /** The changed identities only (added, removed, changed), in id order. */\n differences(): RuntimeFactChange[] {\n return this.changes.filter((change: RuntimeFactChange) => change.status !== RuntimeDiffStatus.UNCHANGED);\n }\n}\n\n/** One vendor library's unresolved uses, gathered before they become a fact. */\nclass ExternalLibraryFacts {\n readonly apis: string[] = [];\n readonly usedBy: string[] = [];\n\n constructor(public readonly level: string) {}\n}\n\n/** Flattens one RuntimeGraph into its facts. */\nexport class RuntimeFactSet {\n readonly facts = new Map<string, RuntimeFact>();\n\n constructor(private readonly graph: RuntimeGraph) {\n this.relationships();\n this.services();\n this.queues();\n this.externals();\n this.remotes();\n this.triggers();\n this.contracts();\n }\n\n private add(fact: RuntimeFact): void {\n const existing = this.facts.get(fact.id);\n if (existing === undefined) {\n this.facts.set(fact.id, fact);\n return;\n }\n // Duplicate relationship facts (two rpc edges between one pair) fold into one, union of values.\n const merged: Record<string, string> = { ...existing.properties };\n for (const [key, value] of Object.entries(fact.properties)) merged[key] = this.set([...this.split(merged[key]), ...this.split(value)]);\n this.facts.set(fact.id, new RuntimeFact(fact.id, fact.kind, fact.category, fact.label, merged));\n }\n\n private relationships(): void {\n for (const edge of this.graph.runtimeEdges) {\n if (edge.type !== 'pubsub') {\n const props: Record<string, string> = { via: this.set(edge.via) };\n if (edge.cutLegacyCycle === true) props['cutLegacyCycle'] = 'true';\n this.add(this.relation(`rpc:${edge.from}->${edge.to}`, 'rpc call', `RPC ${edge.from} → ${edge.to}`, props));\n continue;\n }\n for (const queue of this.queueIds(edge)) {\n this.add(this.relation(`enqueue:${edge.from}->${queue}`, 'enqueue', `Enqueue ${edge.from} → ${queue}`, {}));\n this.add(this.relation(`deliver:${queue}->${edge.to}`, 'delivery', `Deliver ${queue} → ${edge.to}`, {}));\n }\n }\n for (const [id, system] of Object.entries(this.graph.externalSystems ?? {})) {\n for (const user of system.usedBy)\n this.add(this.relation(`external-use:${user}->external-system:${id}`, 'external use', `Uses ${user} → ${system.label}`, {}));\n }\n for (const [name, remote] of Object.entries(this.graph.remoteServices ?? {})) {\n for (const call of remote.calledBy)\n this.add(this.relation(`remote-call:${call.from}->remote-service:${name}#${call.type}`, 'remote call', `Remote ${call.type} ${call.from} → ${name}`, { via: this.set(call.via) }));\n }\n for (const use of this.graph.unresolvedUses) {\n const owner = this.owner(use.api);\n this.add(this.relation(`unresolved-use:${use.service}->${use.api}`, 'unresolved use', `Uses ${use.service} → ${owner}#${use.api}`, { owner }));\n }\n }\n\n /** `queue:Api.method` for a method-level hop; one `contract-queue:Api` per contract otherwise. */\n queueIds(edge: RuntimeEdge): string[] {\n return edge.queue === undefined ? edge.via.map((api: string) => `contract-queue:${api}`) : [`queue:${edge.queue}`];\n }\n\n private services(): void {\n const outgoing = new Map<string, string[]>();\n for (const fact of this.facts.values()) {\n const from = fact.id.slice(fact.id.indexOf(':') + 1).split('->')[0];\n if (this.graph.services[from] === undefined || fact.id.startsWith('deliver:')) continue;\n if (!outgoing.has(from)) outgoing.set(from, []);\n outgoing.get(from)!.push(fact.id.slice(fact.id.indexOf('->') + 2) + (fact.properties['via'] === undefined ? '' : ` [${fact.properties['via']}]`));\n }\n for (const [name, service] of Object.entries(this.graph.services)) {\n this.add(new RuntimeFact(`service:${name}`, RuntimeFactKind.NODE, 'service', `Service ${name}`, {\n level: `L${service.level}`,\n role: this.value(service.role),\n serviceName: this.value(service.serviceName),\n callsService: this.value(service.callsService === undefined ? undefined : this.canonical(service.callsService)),\n implements: this.set(service.implements),\n implementsVia: this.value(service.implementsVia === undefined ? undefined : this.canonical(service.implementsVia)),\n products: this.set(service.products ?? []),\n drawOnGraph: String(service.drawOnGraph !== false),\n outgoing: this.set(outgoing.get(name) ?? []),\n }));\n }\n }\n\n private queues(): void {\n const flow = (queue: RuntimeQueueFlow): Record<string, string> => ({\n level: `L${queue.level}`,\n selfQueue: String(queue.selfQueue),\n producedBy: this.set(queue.producedBy),\n consumedBy: this.set(queue.consumedBy),\n });\n for (const [key, queue] of Object.entries(this.graph.queues)) {\n this.add(this.node(`queue:${key}`, 'queue', `Queue ${key}`, { ...flow(queue), queueName: queue.queueName }));\n }\n for (const [api, queue] of Object.entries(this.graph.contractQueues)) {\n this.add(this.node(`contract-queue:${api}`, 'contract queue', `Contract queue ${api}`, flow(queue)));\n }\n }\n\n private externals(): void {\n for (const [id, system] of Object.entries(this.graph.externalSystems ?? {})) {\n this.add(this.node(`external-system:${id}`, 'external system', `External ${system.label}`, {\n level: `L${system.level}`,\n kind: system.kind,\n label: system.label,\n usedBy: this.set(system.usedBy),\n apis: this.set(system.apis),\n }));\n }\n const libraries = new Map<string, ExternalLibraryFacts>();\n for (const use of this.graph.unresolvedUses) {\n if (this.graph.apis[use.api]?.externalSystem !== undefined) continue;\n const owner = this.owner(use.api);\n if (!libraries.has(owner)) libraries.set(owner, new ExternalLibraryFacts(`L${use.level}`));\n libraries.get(owner)!.apis.push(use.api);\n libraries.get(owner)!.usedBy.push(use.service);\n }\n for (const owner of libraries.keys()) {\n const facts = libraries.get(owner)!;\n this.add(this.node(`external-library:${owner}`, 'external library', `External ${owner}`, {\n level: facts.level,\n apis: this.set(facts.apis),\n usedBy: this.set(facts.usedBy),\n }));\n }\n }\n\n private remotes(): void {\n for (const [name, remote] of Object.entries(this.graph.remoteServices ?? {})) {\n this.add(this.node(`remote-service:${name}`, 'remote service', `Remote service ${name}`, {\n level: `L${remote.level}`,\n label: this.value(remote.label),\n implements: this.set(remote.implements),\n }));\n }\n }\n\n private triggers(): void {\n for (const trigger of this.graph.triggers) {\n const caller = trigger.caller === undefined ? undefined : `${trigger.caller.kind} ${trigger.caller.label}`;\n this.add(this.node(`trigger:${trigger.kind}:${trigger.api}.${trigger.method}@${trigger.service}`, `${trigger.kind} trigger`,\n `${trigger.kind === 'cron' ? 'Cron' : 'External'} ${trigger.api}.${trigger.method} → ${trigger.service}`, {\n level: `L${trigger.level}`,\n queueName: this.value(trigger.queueName),\n caller: this.value(caller),\n }));\n }\n }\n\n private contracts(): void {\n for (const [name, api] of Object.entries(this.graph.apis)) {\n this.add(new RuntimeFact(`api:${name}`, RuntimeFactKind.CONTRACT, 'contract', `Contract ${name}`, {\n implementedBy: this.set(api.implementedBy),\n usedBy: this.set(api.usedBy),\n type: this.value(api.type),\n owner: this.value(api.owner),\n externalSystem: this.value(api.externalSystem === undefined ? undefined : `${api.externalSystem.kind} ${api.externalSystem.label ?? ''}`.trim()),\n }));\n }\n }\n\n private owner(api: string): string {\n return this.graph.apis[api]?.owner ?? api;\n }\n\n private node(id: string, category: string, label: string, properties: Record<string, string>): RuntimeFact {\n return new RuntimeFact(id, RuntimeFactKind.NODE, category, label, properties);\n }\n\n private relation(id: string, category: string, label: string, properties: Record<string, string>): RuntimeFact {\n return new RuntimeFact(id, RuntimeFactKind.RELATIONSHIP, category, label, properties);\n }\n\n /** Set semantics: de-duplicated and sorted, so order alone is never a change. */\n private set(values: string[]): string {\n const unique = [...new Set(values)].sort();\n return unique.length === 0 ? '(none)' : unique.join(', ');\n }\n\n private split(value: string | undefined): string[] {\n return value === undefined || value === '(none)' ? [] : value.split(', ');\n }\n\n private value(value: string | undefined): string {\n return value ?? '(absent)';\n }\n\n /** JSON with sorted keys, for the two map-or-string fields. */\n private canonical(value: string | Record<string, string>): string {\n if (typeof value === 'string') return value;\n return JSON.stringify(Object.keys(value).sort().map((key: string) => [key, value[key]]));\n }\n}\n\n/** Compares two saved runtime graphs, Current → Goal. Pure; deterministic for equivalent inputs. */\nexport class RuntimeGraphDiff {\n compare(current: RuntimeGraph, goal: RuntimeGraph): RuntimeGraphDiffResult {\n const before = new RuntimeFactSet(current).facts;\n const after = new RuntimeFactSet(goal).facts;\n const ids = [...new Set([...before.keys(), ...after.keys()])].sort();\n const changes = ids.map((id: string) => this.change(id, before.get(id), after.get(id)));\n return new RuntimeGraphDiffResult(changes, current.maxLevel, goal.maxLevel);\n }\n\n private change(id: string, before: RuntimeFact | undefined, after: RuntimeFact | undefined): RuntimeFactChange {\n const fact = (after ?? before)!;\n if (before === undefined)\n return new RuntimeFactChange(id, fact.kind, fact.category, fact.label, RuntimeDiffStatus.ADDED, null, after!.properties, []);\n if (after === undefined)\n return new RuntimeFactChange(id, fact.kind, fact.category, fact.label, RuntimeDiffStatus.REMOVED, before.properties, null, []);\n const fields = [...new Set([...Object.keys(before.properties), ...Object.keys(after.properties)])]\n .sort()\n .filter((field: string) => before.properties[field] !== after.properties[field]);\n const status = fields.length === 0 ? RuntimeDiffStatus.UNCHANGED : RuntimeDiffStatus.CHANGED;\n return new RuntimeFactChange(id, fact.kind, fact.category, fact.label, status, before.properties, after.properties, fields);\n }\n}\n"]}
@@ -20,6 +20,8 @@ export declare class RuntimeHtmlPage {
20
20
  * though this page lists only the products it shows.
21
21
  */
22
22
  private shownProducts;
23
+ /** Goal vs Current (#1239): the direction, the counts (or why it is unavailable), the key and every difference. */
24
+ private goalLegend;
23
25
  private edgeKey;
24
26
  private responsibilities;
25
27
  }