@webpieces/nx-webpieces-rules 0.4.911 → 0.4.913

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) 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/index.d.ts +1 -1
  14. package/src/index.js +3 -1
  15. package/src/index.js.map +1 -1
  16. package/src/lib/graph-color-modes.d.ts +15 -1
  17. package/src/lib/graph-color-modes.js +19 -1
  18. package/src/lib/graph-color-modes.js.map +1 -1
  19. package/src/lib/graph-filter.client.d.ts +9 -2
  20. package/src/lib/graph-filter.client.js +15 -0
  21. package/src/lib/graph-filter.client.js.map +1 -1
  22. package/src/lib/graph-legend.js +1 -1
  23. package/src/lib/graph-legend.js.map +1 -1
  24. package/src/lib/graph-mode-state.client.d.ts +9 -2
  25. package/src/lib/graph-mode-state.client.js +17 -4
  26. package/src/lib/graph-mode-state.client.js.map +1 -1
  27. package/src/lib/graph-page-shell.d.ts +11 -4
  28. package/src/lib/graph-page-shell.js +11 -9
  29. package/src/lib/graph-page-shell.js.map +1 -1
  30. package/src/lib/graph-products.d.ts +22 -3
  31. package/src/lib/graph-products.js +63 -13
  32. package/src/lib/graph-products.js.map +1 -1
  33. package/src/lib/graph-render-model.d.ts +41 -0
  34. package/src/lib/graph-render-model.js +45 -1
  35. package/src/lib/graph-render-model.js.map +1 -1
  36. package/src/lib/graph-visualizer.client.d.ts +7 -1
  37. package/src/lib/graph-visualizer.client.js +37 -4
  38. package/src/lib/graph-visualizer.client.js.map +1 -1
  39. package/src/lib/graph-visualizer.js +1 -1
  40. package/src/lib/graph-visualizer.js.map +1 -1
  41. package/src/lib/runtime-goal-comparison.d.ts +55 -0
  42. package/src/lib/runtime-goal-comparison.js +209 -0
  43. package/src/lib/runtime-goal-comparison.js.map +1 -0
  44. package/src/lib/runtime-goal-details.d.ts +17 -0
  45. package/src/lib/runtime-goal-details.js +118 -0
  46. package/src/lib/runtime-goal-details.js.map +1 -0
  47. package/src/lib/runtime-goal-file.d.ts +72 -0
  48. package/src/lib/runtime-goal-file.js +201 -0
  49. package/src/lib/runtime-goal-file.js.map +1 -0
  50. package/src/lib/runtime-goal-styles.d.ts +10 -0
  51. package/src/lib/runtime-goal-styles.js +25 -0
  52. package/src/lib/runtime-goal-styles.js.map +1 -0
  53. package/src/lib/runtime-goal-validator.d.ts +39 -0
  54. package/src/lib/runtime-goal-validator.js +236 -0
  55. package/src/lib/runtime-goal-validator.js.map +1 -0
  56. package/src/lib/runtime-goal-view.d.ts +22 -0
  57. package/src/lib/runtime-goal-view.js +64 -0
  58. package/src/lib/runtime-goal-view.js.map +1 -0
  59. package/src/lib/runtime-graph-diff.d.ts +107 -0
  60. package/src/lib/runtime-graph-diff.js +346 -0
  61. package/src/lib/runtime-graph-diff.js.map +1 -0
  62. package/src/lib/runtime-html-page.d.ts +8 -0
  63. package/src/lib/runtime-html-page.js +39 -6
  64. package/src/lib/runtime-html-page.js.map +1 -1
  65. package/src/lib/runtime-layout.d.ts +2 -0
  66. package/src/lib/runtime-layout.js +4 -0
  67. package/src/lib/runtime-layout.js.map +1 -1
  68. package/src/lib/runtime-union-graph.d.ts +20 -0
  69. package/src/lib/runtime-union-graph.js +94 -0
  70. package/src/lib/runtime-union-graph.js.map +1 -0
  71. package/src/lib/runtime-viewer-adapter.js +7 -5
  72. package/src/lib/runtime-viewer-adapter.js.map +1 -1
  73. package/src/lib/runtime-visualizer.client.js +7 -3
  74. package/src/lib/runtime-visualizer.client.js.map +1 -1
  75. package/src/lib/runtime-visualizer.d.ts +8 -3
  76. package/src/lib/runtime-visualizer.js +18 -10
  77. package/src/lib/runtime-visualizer.js.map +1 -1
  78. package/src/lib/runtime-viz-options.d.ts +28 -1
  79. package/src/lib/runtime-viz-options.js +36 -2
  80. package/src/lib/runtime-viz-options.js.map +1 -1
  81. package/src/plugin.js +2 -2
  82. package/src/plugin.js.map +1 -1
  83. package/src/runtime-targets.d.ts +6 -0
  84. package/src/runtime-targets.js +17 -0
  85. package/src/runtime-targets.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"graph-visualizer.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-visualizer.ts"],"names":[],"mappings":"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","sourcesContent":["import { GraphNavigation, NavigationLayout } from './graph-navigation';\n/**\n * Graph Visualizer\n *\n * Generates visual representations of the architecture graph:\n * - DOT format (for Graphviz)\n * - Interactive HTML (using viz.js)\n *\n * All behavior lives on the injectable GraphVisualizer class so webpieces DI +\n * @DocumentDesign can wire it — module-scope functions are a dead end the DI\n * graph can't reach.\n */\n\nimport * as fs from 'fs';\nimport { SavedSnapshot } from './saved-snapshot';\nimport * as path from 'path';\nimport { execSync } from 'child_process';\nimport type { EnhancedGraph } from './graph-sorter';\nimport type { ApiRef, ApiRelation, ApiRelationKind } from './api-usage/api-relations';\nimport { GraphNames, NodeIdOwner } from './graph-names';\nimport { LevelBand, LevelBandLayout } from './graph-level-bands';\nimport { ProjectAdjacency, ProjectCycleDetector } from './graph-cycles';\nimport { ResponsibilitiesRenderer } from './graph-responsibilities';\nimport { GraphNodeMenu } from './graph-node-menu';\nimport { dotValue } from './dot-syntax';\nimport { GraphRenderModel, GraphFilterAssets } from './graph-render-model';\nimport { NodeFacts, NodeModeStyler, ProductCount } from './graph-color-modes';\nimport { ProductBoundary, ProductPalette } from './graph-products';\nimport { ProductDependencyMatrix } from './product-dependencies';\nimport { GraphLegend } from './graph-legend';\nimport { GraphPageShell, ShellParts } from './graph-page-shell';\nimport { GraphPageStyles } from './graph-page-styles';\nimport { IMPACT_SIDECAR_SRC } from './graph-impact';\nimport { toError } from '../toError';\n\n/**\n * Directory (repo-relative) that the committed architecture HTML lives in.\n * Node click-through links are computed relative to this so they resolve when\n * the file is opened straight from the checkout.\n */\nconst ARCH_OUTPUT_DIR = 'architecture';\n\n/** Contracts named on one `implements` edge label before it truncates to \"+N more\". */\nconst MAX_EDGE_LABEL_APIS = 4;\n\n/**\n * One node's design page, handed to the browser so the node menu can offer \"View Design\" for the\n * boxes that HAVE one and omit the item entirely for the boxes that do not.\n *\n * The link is data on the PAGE now, not a `URL=` attribute in the DOT: a URL made viz.js wrap the\n * box in an `<a>` and clicking navigated straight out, which the menu replaces.\n */\nexport class DesignLink {\n constructor(\n public readonly nodeId: string,\n public readonly href: string,\n ) {}\n}\n\nexport class VisualizationPaths {\n htmlPath: string;\n\n constructor(htmlPath: string) {\n this.htmlPath = htmlPath;\n }\n}\n\n/**\n * The token the client scripts carry where the DOT belongs. It must appear EXACTLY ONCE in a compiled\n * client — the inliner is a blind split/join, so a second occurrence (in a comment, say) would be\n * replaced by the entire DOT too, bloating every generated page.\n */\nexport const CLIENT_MODEL_PLACEHOLDER = '__' + 'RENDER_MODEL' + '__';\n\n/** Same contract as CLIENT_MODEL_PLACEHOLDER, for the node → design.html links the menu offers. */\nexport const CLIENT_DESIGN_LINKS_PLACEHOLDER = '__' + 'DESIGN_LINKS' + '__';\n\n/**\n * Read a compiled browser client sitting beside this file.\n *\n * It is generated from the matching `.client.ts` by tsc, so it exists in `dist` and in the published\n * tarball but NOT in a source checkout. The error says that outright rather than surfacing a bare\n * ENOENT, because \"the build has not run\" and \"the file is missing\" look identical otherwise.\n */\n// webpieces-disable no-function-outside-class -- module-level resolver for the default injected into GraphVisualizer/RuntimeHtmlPage; making it a class would need a container in a module both of them load eagerly\nexport function readCompiledClient(name: string): string {\n const file = path.join(__dirname, name);\n if (!fs.existsSync(file)) {\n throw new Error(\n `${name} not found beside ${__dirname}. It is COMPILED from ${name.replace(/\\.js$/, '.ts')} ` +\n 'by tsc, so it only exists after a build — run the package build, or inject the text.',\n );\n }\n const source = fs.readFileSync(file, 'utf-8');\n return name === 'graph-visualizer.client.js' ? readCompiledClient('graph-mode-state.client.js') + source : source;\n}\n\nexport class GraphVisualizer {\n private readonly filterAssets = new GraphFilterAssets();\n private readonly snapshot = new SavedSnapshot();\n private readonly names = new GraphNames();\n private readonly responsibilities = new ResponsibilitiesRenderer();\n private readonly bandLayout = new LevelBandLayout();\n private readonly cycles = new ProjectCycleDetector();\n /** The ONE floating-node-menu implementation, shared with the per-project design pages. */\n private readonly nodeMenu = new GraphNodeMenu();\n private readonly styler = new NodeModeStyler();\n private readonly legend = new GraphLegend();\n private readonly shell = new GraphPageShell();\n private readonly pageStyles = new GraphPageStyles();\n private readonly navigation = new GraphNavigation(NavigationLayout.FLOATING);\n private readonly boundary = new ProductBoundary();\n\n /**\n * How to obtain the browser client's text. Injected so HTML generation does not depend on BUILD\n * ORDER: the default reads the compiled sibling, which exists in the tarball and in dist but NOT in\n * a source checkout (the source there is .client.ts). A unit test running from source supplies the\n * text itself rather than requiring the package to have been built first.\n */\n constructor(\n private readonly clientJs: () => string = (): string =>\n readCompiledClient('graph-visualizer.client.js'),\n private readonly filterJs: () => string = (): string =>\n readCompiledClient('graph-filter.client.js'),\n ) {}\n\n /**\n * A project tagged `drawOnGraph:false` is hidden from the rendered graph —\n * its node, its rank placement, its lock-search option, its responsibilities\n * card, and every edge touching it are all omitted. It stays in the JSON.\n */\n private isHidden(entry: EnhancedGraph[string]): boolean {\n return entry.drawOnGraph === false;\n }\n\n /**\n * Edge styling by API-relation kind (why the edge exists):\n * implements → BLACK dashed (a controller serves this api-lib's contract)\n * uses → BLACK solid (a generated client calls it) — same as a\n * plain library import, since a plain dependency IS a use.\n * uses-implements → BLUE dashed, thicker (does both — implements some\n * contracts of the api-lib, uses others)\n * plain lib (none) → the default thin black solid arrow, unchanged.\n * `kind` is undefined for every non-api-lib dependency edge.\n */\n private edgeAttrs(kind: ApiRelationKind | undefined): string {\n if (kind === 'implements') return 'style=dashed';\n if (kind === 'uses-implements') return 'style=dashed, color=\"#1976d2\", penwidth=2';\n return '';\n }\n\n /**\n * The DOT attribute list for ONE dependency edge. An edge that IMPLEMENTS contracts is also\n * LABELED with them: the dashed line alone says \"something here is implemented\", which reads as\n * \"the tool did not detect anything\" to everyone who has not memorized the legend. Naming the\n * contracts makes `auth-store-api` visibly resolve to the server that serves it — the single\n * most important relationship in a microservice architecture, and the one the diagram was\n * silent about.\n */\n private edgeDot(from: string, to: string, relation: ApiRelation | undefined): string {\n const attrs: string[] = [];\n const styling = this.edgeAttrs(relation?.kind);\n if (styling !== '') attrs.push(styling);\n const served = (relation?.implements ?? []).map((ref: ApiRef) => ref.api);\n if (served.length > 0)\n attrs.push(`label=\"implements: ${this.labelledApis(served)}\", fontsize=9`);\n const suffix = attrs.length === 0 ? '' : ` [${attrs.join(', ')}]`;\n return ` \"${dotValue(from)}\" -> \"${dotValue(to)}\"${suffix};\\n`;\n }\n\n /**\n * The contract names for an edge label, sorted and capped so a shared api-lib serving a dozen\n * contracts cannot blow the edge label up into a wall of text. The truncation is stated in the\n * label (\"+N more\") rather than silent — the full list is in dependencies.json.\n */\n private labelledApis(apis: string[]): string {\n const sorted = [...apis].sort();\n if (sorted.length <= MAX_EDGE_LABEL_APIS) return sorted.join(', ');\n const shown = sorted.slice(0, MAX_EDGE_LABEL_APIS).join(', ');\n return `${shown} +${sorted.length - MAX_EDGE_LABEL_APIS} more`;\n }\n\n /**\n * Href for a node's design page: the project's committed design.html, made\n * relative to architecture/dependencies.html. Returns null when the project\n * has no generated DI design (no design.json → no design page exists).\n */\n private designHtmlHref(designFile: string | undefined): string | null {\n if (!designFile) return null;\n const designHtml = designFile.replace(/design\\.json$/, 'design.html');\n return path.posix.relative(ARCH_OUTPUT_DIR, designHtml);\n }\n\n /**\n * The design pages that EXIST, one entry per visible node that has one. A node absent from this\n * list gets no \"View Design\" item at all — the item is never rendered dead or greyed out.\n */\n designLinks(graph: EnhancedGraph): DesignLink[] {\n const links: DesignLink[] = [];\n for (const project of Object.keys(graph)) {\n const info = graph[project];\n if (this.isHidden(info)) continue;\n const href = this.designHtmlHref(info.designFile);\n if (href === null) continue;\n links.push(new DesignLink(this.names.getNodeId(project), href));\n }\n return links;\n }\n\n /**\n * Generate Graphviz DOT format from the graph\n */\n generateDot(graph: EnhancedGraph, title: string = 'Monorepo Dependency Architecture'): string {\n return this.generateRenderModel(graph, title).fullDot;\n }\n\n generateRenderModel(\n graph: EnhancedGraph,\n title: string = 'Monorepo Dependency Architecture',\n ): GraphRenderModel {\n this.assertDrawable(graph);\n const model = new GraphRenderModel();\n let dot = 'digraph Architecture {\\n';\n dot += ' rankdir=TB;\\n';\n dot += ' node [shape=box, style=filled, fontname=\"Arial\"];\\n';\n dot += ' edge [fontname=\"Arial\"];\\n\\n';\n\n model.header = dot;\n const bands = this.levelBands(graph);\n model.bands = bands;\n\n const palette = ProductPalette.fromGraph(graph);\n dot += this.dotNodes(graph, model, palette);\n dot += '\\n';\n dot += this.bandLayout.dot(bands);\n dot += '\\n';\n dot += this.dotEdges(graph, model, palette);\n\n const footerStart = dot.length;\n dot += '\\n labelloc=\"t\";\\n';\n dot += ` label=\"${dotValue(title)}\\\\n(from architecture/dependencies.json)\";\\n`;\n dot += ' fontsize=20;\\n';\n dot += '}\\n';\n\n model.footer = dot.slice(footerStart);\n model.completeEndpoints();\n model.fullDot = dot;\n return model;\n }\n\n /**\n * Refuse to draw a graph that would render something false.\n *\n * Two conditions, both of which produced a confidently-wrong picture with no warning at all:\n * - two projects sharing a node id fuse into one box, which UNIONS their two rank sets and\n * collapses two whole dependency levels onto one row (see graph-names.ts);\n * - a cycle makes the level numbers every row is keyed on meaningless (see graph-cycles.ts).\n */\n private assertDrawable(graph: EnhancedGraph): void {\n const owners: NodeIdOwner[] = [];\n const adjacency: ProjectAdjacency = {};\n for (const project of Object.keys(graph)) {\n owners.push(new NodeIdOwner(project, graph[project].level));\n adjacency[project] = graph[project].dependsOn ?? [];\n }\n this.names.assertUniqueNodeIds(owners);\n this.cycles.assertAcyclic(adjacency, 'architecture/dependencies.json');\n }\n\n /**\n * The visible projects grouped into one band per dependency level, ordered HIGHEST LEVEL FIRST\n * so the emitted bands read top-to-bottom with L0 last (hidden projects are omitted, so no\n * stray rank=same name is emitted for an absent node). LevelBandLayout turns these into the\n * rank sets and the invisible chain that pins them — see graph-level-bands.ts for why the\n * chain is required at all.\n */\n private levelBands(graph: EnhancedGraph): LevelBand[] {\n const byLevel = new Map<number, string[]>();\n for (const project of Object.keys(graph)) {\n if (this.isHidden(graph[project])) continue;\n const level = graph[project].level;\n const nodeIds = byLevel.get(level);\n if (nodeIds === undefined) byLevel.set(level, [this.names.getNodeId(project)]);\n else nodeIds.push(this.names.getNodeId(project));\n }\n const levels = [...byLevel.keys()].sort((a: number, b: number): number => b - a);\n return levels.map(\n (level: number): LevelBand =>\n new LevelBand(level, [...(byLevel.get(level) as string[])].sort()),\n );\n }\n\n // Node lines: one statement per color mode (graph-color-modes.ts) — the label is the short\n // name plus a short meta line, because the fill now shows what the env list used to spell out.\n // No node carries a URL: EVERY box is clickable and opens the floating node menu instead, which\n // is where a design page is reached (see designLinks).\n private dotNodes(graph: EnhancedGraph, model: GraphRenderModel, palette: ProductPalette): string {\n let dot = '';\n for (const project of Object.keys(graph)) {\n const info = graph[project];\n if (this.isHidden(info)) continue;\n // Identity is the project key; the LABEL is the pretty short name.\n const facts = new NodeFacts(\n this.names.getNodeId(project),\n this.names.getShortName(project),\n info.level,\n info.role ?? 'lib',\n info.framework ?? [],\n info.products ?? [],\n );\n this.styler.record(model.legend, facts, palette);\n dot += model.styledNode(facts, this.styler.dots(facts, palette));\n }\n return dot;\n }\n\n // Edge lines (dependencies). An edge to an api-lib is styled by WHY it exists\n // (implements/uses/uses-implements, from apiRelations); every other dependency\n // keeps the default plain arrow. In the Product color mode an edge crossing into another\n // product is ALSO dashed in that product's color (#1204), so product boundaries read at a glance.\n private dotEdges(graph: EnhancedGraph, model: GraphRenderModel, palette: ProductPalette): string {\n let dot = '';\n for (const project of Object.keys(graph)) {\n const info = graph[project];\n if (this.isHidden(info)) continue;\n const nodeId = this.names.getNodeId(project);\n for (const dep of info.dependsOn || []) {\n // Both endpoints must be visible — an edge to/from a hidden box\n // is dropped so no connection dangles into empty space.\n if (graph[dep] !== undefined && this.isHidden(graph[dep])) continue;\n dot += model.edge(\n nodeId,\n this.names.getNodeId(dep),\n this.edgeDot(nodeId, this.names.getNodeId(dep), info.apiRelations?.[dep]),\n this.crossProductAttrs(info.products ?? [], graph[dep]?.products ?? [], model, palette),\n );\n }\n }\n return dot;\n }\n\n /**\n * The Product color mode's extra attributes for one dependency: dashed, thicker and in the color\n * of the product it crosses into, or '' for an edge that stays inside its source's products.\n */\n private crossProductAttrs(\n from: readonly string[],\n to: readonly string[],\n model: GraphRenderModel,\n palette: ProductPalette,\n ): string {\n const into = this.boundary.crossedInto(from, to);\n if (into === null) return '';\n model.legend.crossProductEdges++;\n return `style=dashed, color=\"${palette.colorOf(into).color}\", penwidth=2`;\n }\n\n /**\n * Generate the interactive page: the drawer shell around a viz.js-rendered graph.\n *\n * The Impact sidecar is a plain `<script src>` loaded BEFORE the page scripts, so the page knows\n * the branch's impact when it first draws. It is per-branch and gitignored (graph-impact.ts):\n * when it is absent the browser skips it and Impact is disabled with its reason.\n */\n generateHTML(\n model: GraphRenderModel,\n links: DesignLink[],\n title: string = 'Monorepo Dependency Architecture',\n lockControl: string = '',\n responsibilitiesHtml: string = '',\n ): string {\n const parts = new ShellParts(\n title,\n lockControl,\n this.legend.sections(model.legend),\n this.legend.edgeKey(),\n this.filterAssets.html(),\n this.snapshot.html(),\n responsibilitiesHtml,\n model.legend.products.map((count: ProductCount): string => count.product),\n );\n return `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>${title}</title>\n <script src=\"https://cdn.jsdelivr.net/npm/@viz-js/viz@3.28.0/dist/viz-global.js\"></script>\n <script src=\"${IMPACT_SIDECAR_SRC}\"></script>\n <style>${this.styles()}</style>\n</head>\n<body>\n ${this.shell.body(parts)}\n <script>${this.nodeMenu.script()}</script>\n <script>${this.filterJs()}</script>\n <script>${this.navigation.script()}</script>\n <script>${this.script(model, links)}</script>\n</body>\n</html>`;\n }\n\n /** Shared menu/dim/filter/zoom rules first, then the page's own, so its `#graph` rules win. */\n private styles(): string {\n return (\n this.nodeMenu.styles() +\n this.nodeMenu.dimStyles('#graph') +\n this.filterAssets.styles() +\n this.navigation.styles() +\n this.pageStyles.css()\n );\n }\n\n /**\n * The drawer's type-to-search lock field, replacing a `<select>` that listed every project and\n * was unusable at hundreds of options. Picking a project LOCKS the graph into that box's hover\n * view — its full ancestor + descendant chain stays lit while everything else dims — and narrows\n * the responsibilities panel to that chain. Clearing the field, or Esc, unlocks.\n *\n * Each option's VALUE is the node id the SVG is keyed on; its label is the level and short name.\n * Options are ordered by level DESCENDING to match the responsibilities cards.\n */\n lockControl(graph: EnhancedGraph): string {\n const projects = Object.keys(graph);\n projects.sort((a: string, b: string): number => {\n const levelDiff = graph[b].level - graph[a].level;\n if (levelDiff !== 0) return levelDiff;\n return a.localeCompare(b);\n });\n let options = '';\n for (const project of projects) {\n if (this.isHidden(graph[project])) continue;\n const nodeId = this.escapeHtml(this.names.getNodeId(project));\n const shortName = this.escapeHtml(this.names.getShortName(project));\n options += `<option value=\"${nodeId}\">L${graph[project].level} · ${shortName}</option>`;\n }\n return (\n '<input type=\"search\" id=\"wp-lock\" list=\"wp-lock-options\" placeholder=\"Lock a project… ( / )\" ' +\n 'autocomplete=\"off\" spellcheck=\"false\">' +\n `<datalist id=\"wp-lock-options\">${options}</datalist>`\n );\n }\n\n private escapeHtml(text: string): string {\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n }\n\n /**\n * The page script. The browser code lives in graph-visualizer.client.ts — real, linted TypeScript\n * that tsc compiles in place, so what this inlines is its COMPILED .js sitting beside this file.\n *\n * The substitution is a blind split/join, which is why the placeholder token must appear EXACTLY\n * ONCE in the client (never in one of its comments): every literal occurrence would otherwise be\n * replaced by the whole DOT.\n */\n private script(model: GraphRenderModel, links: DesignLink[]): string {\n return this.clientJs()\n .split(CLIENT_MODEL_PLACEHOLDER)\n .join(this.filterAssets.json(model))\n .split(CLIENT_DESIGN_LINKS_PLACEHOLDER)\n .join(this.filterAssets.json(links));\n }\n\n /**\n * Write the committed architecture visualization to\n * architecture/dependencies.html, next to dependencies.json.\n *\n * This is a checked-in artifact, regenerated deterministically by\n * architecture:generate so every box keeps its menu, and the \"View Design\"\n * item keeps pointing at each project's committed design.html as designs\n * come and go. The DOT is embedded in the HTML (rendered client-side by\n * viz.js). Output is deterministic (sorted graph in → same bytes out) so git\n * only shows a diff when the architecture actually changed.\n *\n * `productDependencies` is the `product-tags` rule's matrix, listed in the Product legend; null\n * when the rule is OFF, and the legend then lists no matrix.\n */\n writeVisualization(\n graph: EnhancedGraph,\n workspaceRoot: string,\n productDependencies: ProductDependencyMatrix | null,\n title: string = 'Monorepo Dependency Architecture',\n ): VisualizationPaths {\n const outputDir = path.join(workspaceRoot, ARCH_OUTPUT_DIR);\n\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n const lockControl = this.lockControl(graph);\n const responsibilities = this.responsibilities.generateSection(graph, workspaceRoot);\n const model = this.generateRenderModel(graph, title);\n model.legend.productDependencies = productDependencies === null ? null : [...productDependencies.entries];\n const html = this.generateHTML(\n model,\n this.designLinks(graph),\n title,\n lockControl,\n responsibilities,\n );\n const htmlPath = path.join(outputDir, 'dependencies.html');\n fs.writeFileSync(htmlPath, html, 'utf-8');\n\n return new VisualizationPaths(htmlPath);\n }\n\n /**\n * Open the HTML visualization in the default browser\n */\n openVisualization(htmlPath: string): boolean {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const platform = process.platform;\n let openCommand: string;\n\n if (platform === 'darwin') {\n openCommand = `open \"${htmlPath}\"`;\n } else if (platform === 'win32') {\n openCommand = `start \"\" \"${htmlPath}\"`;\n } else {\n openCommand = `xdg-open \"${htmlPath}\"`;\n }\n\n execSync(openCommand, { stdio: 'ignore' });\n return true;\n } catch (err: unknown) {\n const error = toError(err);\n console.warn(`⚠️ Could not open browser: ${error.message}`);\n return false;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"graph-visualizer.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-visualizer.ts"],"names":[],"mappings":"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","sourcesContent":["import { GraphNavigation, NavigationLayout } from './graph-navigation';\n/**\n * Graph Visualizer\n *\n * Generates visual representations of the architecture graph:\n * - DOT format (for Graphviz)\n * - Interactive HTML (using viz.js)\n *\n * All behavior lives on the injectable GraphVisualizer class so webpieces DI +\n * @DocumentDesign can wire it — module-scope functions are a dead end the DI\n * graph can't reach.\n */\n\nimport * as fs from 'fs';\nimport { SavedSnapshot } from './saved-snapshot';\nimport * as path from 'path';\nimport { execSync } from 'child_process';\nimport type { EnhancedGraph } from './graph-sorter';\nimport type { ApiRef, ApiRelation, ApiRelationKind } from './api-usage/api-relations';\nimport { GraphNames, NodeIdOwner } from './graph-names';\nimport { LevelBand, LevelBandLayout } from './graph-level-bands';\nimport { ProjectAdjacency, ProjectCycleDetector } from './graph-cycles';\nimport { ResponsibilitiesRenderer } from './graph-responsibilities';\nimport { GraphNodeMenu } from './graph-node-menu';\nimport { dotValue } from './dot-syntax';\nimport { GraphRenderModel, GraphFilterAssets } from './graph-render-model';\nimport { NodeFacts, NodeModeStyler } from './graph-color-modes';\nimport { ProductBoundary, ProductPalette } from './graph-products';\nimport { ProductDependencyMatrix } from './product-dependencies';\nimport { GraphLegend } from './graph-legend';\nimport { GraphPageShell, ShellParts } from './graph-page-shell';\nimport { GraphPageStyles } from './graph-page-styles';\nimport { IMPACT_SIDECAR_SRC } from './graph-impact';\nimport { toError } from '../toError';\n\n/**\n * Directory (repo-relative) that the committed architecture HTML lives in.\n * Node click-through links are computed relative to this so they resolve when\n * the file is opened straight from the checkout.\n */\nconst ARCH_OUTPUT_DIR = 'architecture';\n\n/** Contracts named on one `implements` edge label before it truncates to \"+N more\". */\nconst MAX_EDGE_LABEL_APIS = 4;\n\n/**\n * One node's design page, handed to the browser so the node menu can offer \"View Design\" for the\n * boxes that HAVE one and omit the item entirely for the boxes that do not.\n *\n * The link is data on the PAGE now, not a `URL=` attribute in the DOT: a URL made viz.js wrap the\n * box in an `<a>` and clicking navigated straight out, which the menu replaces.\n */\nexport class DesignLink {\n constructor(\n public readonly nodeId: string,\n public readonly href: string,\n ) {}\n}\n\nexport class VisualizationPaths {\n htmlPath: string;\n\n constructor(htmlPath: string) {\n this.htmlPath = htmlPath;\n }\n}\n\n/**\n * The token the client scripts carry where the DOT belongs. It must appear EXACTLY ONCE in a compiled\n * client — the inliner is a blind split/join, so a second occurrence (in a comment, say) would be\n * replaced by the entire DOT too, bloating every generated page.\n */\nexport const CLIENT_MODEL_PLACEHOLDER = '__' + 'RENDER_MODEL' + '__';\n\n/** Same contract as CLIENT_MODEL_PLACEHOLDER, for the node → design.html links the menu offers. */\nexport const CLIENT_DESIGN_LINKS_PLACEHOLDER = '__' + 'DESIGN_LINKS' + '__';\n\n/**\n * Read a compiled browser client sitting beside this file.\n *\n * It is generated from the matching `.client.ts` by tsc, so it exists in `dist` and in the published\n * tarball but NOT in a source checkout. The error says that outright rather than surfacing a bare\n * ENOENT, because \"the build has not run\" and \"the file is missing\" look identical otherwise.\n */\n// webpieces-disable no-function-outside-class -- module-level resolver for the default injected into GraphVisualizer/RuntimeHtmlPage; making it a class would need a container in a module both of them load eagerly\nexport function readCompiledClient(name: string): string {\n const file = path.join(__dirname, name);\n if (!fs.existsSync(file)) {\n throw new Error(\n `${name} not found beside ${__dirname}. It is COMPILED from ${name.replace(/\\.js$/, '.ts')} ` +\n 'by tsc, so it only exists after a build — run the package build, or inject the text.',\n );\n }\n const source = fs.readFileSync(file, 'utf-8');\n return name === 'graph-visualizer.client.js' ? readCompiledClient('graph-mode-state.client.js') + source : source;\n}\n\nexport class GraphVisualizer {\n private readonly filterAssets = new GraphFilterAssets();\n private readonly snapshot = new SavedSnapshot();\n private readonly names = new GraphNames();\n private readonly responsibilities = new ResponsibilitiesRenderer();\n private readonly bandLayout = new LevelBandLayout();\n private readonly cycles = new ProjectCycleDetector();\n /** The ONE floating-node-menu implementation, shared with the per-project design pages. */\n private readonly nodeMenu = new GraphNodeMenu();\n private readonly styler = new NodeModeStyler();\n private readonly legend = new GraphLegend();\n private readonly shell = new GraphPageShell();\n private readonly pageStyles = new GraphPageStyles();\n private readonly navigation = new GraphNavigation(NavigationLayout.FLOATING);\n private readonly boundary = new ProductBoundary();\n\n /**\n * How to obtain the browser client's text. Injected so HTML generation does not depend on BUILD\n * ORDER: the default reads the compiled sibling, which exists in the tarball and in dist but NOT in\n * a source checkout (the source there is .client.ts). A unit test running from source supplies the\n * text itself rather than requiring the package to have been built first.\n */\n constructor(\n private readonly clientJs: () => string = (): string =>\n readCompiledClient('graph-visualizer.client.js'),\n private readonly filterJs: () => string = (): string =>\n readCompiledClient('graph-filter.client.js'),\n ) {}\n\n /**\n * A project tagged `drawOnGraph:false` is hidden from the rendered graph —\n * its node, its rank placement, its lock-search option, its responsibilities\n * card, and every edge touching it are all omitted. It stays in the JSON.\n */\n private isHidden(entry: EnhancedGraph[string]): boolean {\n return entry.drawOnGraph === false;\n }\n\n /**\n * Edge styling by API-relation kind (why the edge exists):\n * implements → BLACK dashed (a controller serves this api-lib's contract)\n * uses → BLACK solid (a generated client calls it) — same as a\n * plain library import, since a plain dependency IS a use.\n * uses-implements → BLUE dashed, thicker (does both — implements some\n * contracts of the api-lib, uses others)\n * plain lib (none) → the default thin black solid arrow, unchanged.\n * `kind` is undefined for every non-api-lib dependency edge.\n */\n private edgeAttrs(kind: ApiRelationKind | undefined): string {\n if (kind === 'implements') return 'style=dashed';\n if (kind === 'uses-implements') return 'style=dashed, color=\"#1976d2\", penwidth=2';\n return '';\n }\n\n /**\n * The DOT attribute list for ONE dependency edge. An edge that IMPLEMENTS contracts is also\n * LABELED with them: the dashed line alone says \"something here is implemented\", which reads as\n * \"the tool did not detect anything\" to everyone who has not memorized the legend. Naming the\n * contracts makes `auth-store-api` visibly resolve to the server that serves it — the single\n * most important relationship in a microservice architecture, and the one the diagram was\n * silent about.\n */\n private edgeDot(from: string, to: string, relation: ApiRelation | undefined): string {\n const attrs: string[] = [];\n const styling = this.edgeAttrs(relation?.kind);\n if (styling !== '') attrs.push(styling);\n const served = (relation?.implements ?? []).map((ref: ApiRef) => ref.api);\n if (served.length > 0)\n attrs.push(`label=\"implements: ${this.labelledApis(served)}\", fontsize=9`);\n const suffix = attrs.length === 0 ? '' : ` [${attrs.join(', ')}]`;\n return ` \"${dotValue(from)}\" -> \"${dotValue(to)}\"${suffix};\\n`;\n }\n\n /**\n * The contract names for an edge label, sorted and capped so a shared api-lib serving a dozen\n * contracts cannot blow the edge label up into a wall of text. The truncation is stated in the\n * label (\"+N more\") rather than silent — the full list is in dependencies.json.\n */\n private labelledApis(apis: string[]): string {\n const sorted = [...apis].sort();\n if (sorted.length <= MAX_EDGE_LABEL_APIS) return sorted.join(', ');\n const shown = sorted.slice(0, MAX_EDGE_LABEL_APIS).join(', ');\n return `${shown} +${sorted.length - MAX_EDGE_LABEL_APIS} more`;\n }\n\n /**\n * Href for a node's design page: the project's committed design.html, made\n * relative to architecture/dependencies.html. Returns null when the project\n * has no generated DI design (no design.json → no design page exists).\n */\n private designHtmlHref(designFile: string | undefined): string | null {\n if (!designFile) return null;\n const designHtml = designFile.replace(/design\\.json$/, 'design.html');\n return path.posix.relative(ARCH_OUTPUT_DIR, designHtml);\n }\n\n /**\n * The design pages that EXIST, one entry per visible node that has one. A node absent from this\n * list gets no \"View Design\" item at all — the item is never rendered dead or greyed out.\n */\n designLinks(graph: EnhancedGraph): DesignLink[] {\n const links: DesignLink[] = [];\n for (const project of Object.keys(graph)) {\n const info = graph[project];\n if (this.isHidden(info)) continue;\n const href = this.designHtmlHref(info.designFile);\n if (href === null) continue;\n links.push(new DesignLink(this.names.getNodeId(project), href));\n }\n return links;\n }\n\n /**\n * Generate Graphviz DOT format from the graph\n */\n generateDot(graph: EnhancedGraph, title: string = 'Monorepo Dependency Architecture'): string {\n return this.generateRenderModel(graph, title).fullDot;\n }\n\n generateRenderModel(\n graph: EnhancedGraph,\n title: string = 'Monorepo Dependency Architecture',\n ): GraphRenderModel {\n this.assertDrawable(graph);\n const model = new GraphRenderModel();\n let dot = 'digraph Architecture {\\n';\n dot += ' rankdir=TB;\\n';\n dot += ' node [shape=box, style=filled, fontname=\"Arial\"];\\n';\n dot += ' edge [fontname=\"Arial\"];\\n\\n';\n\n model.header = dot;\n const bands = this.levelBands(graph);\n model.bands = bands;\n\n const palette = ProductPalette.fromGraph(graph);\n dot += this.dotNodes(graph, model, palette);\n dot += '\\n';\n dot += this.bandLayout.dot(bands);\n dot += '\\n';\n dot += this.dotEdges(graph, model, palette);\n\n const footerStart = dot.length;\n dot += '\\n labelloc=\"t\";\\n';\n dot += ` label=\"${dotValue(title)}\\\\n(from architecture/dependencies.json)\";\\n`;\n dot += ' fontsize=20;\\n';\n dot += '}\\n';\n\n model.footer = dot.slice(footerStart);\n model.completeEndpoints();\n model.fullDot = dot;\n return model;\n }\n\n /**\n * Refuse to draw a graph that would render something false.\n *\n * Two conditions, both of which produced a confidently-wrong picture with no warning at all:\n * - two projects sharing a node id fuse into one box, which UNIONS their two rank sets and\n * collapses two whole dependency levels onto one row (see graph-names.ts);\n * - a cycle makes the level numbers every row is keyed on meaningless (see graph-cycles.ts).\n */\n private assertDrawable(graph: EnhancedGraph): void {\n const owners: NodeIdOwner[] = [];\n const adjacency: ProjectAdjacency = {};\n for (const project of Object.keys(graph)) {\n owners.push(new NodeIdOwner(project, graph[project].level));\n adjacency[project] = graph[project].dependsOn ?? [];\n }\n this.names.assertUniqueNodeIds(owners);\n this.cycles.assertAcyclic(adjacency, 'architecture/dependencies.json');\n }\n\n /**\n * The visible projects grouped into one band per dependency level, ordered HIGHEST LEVEL FIRST\n * so the emitted bands read top-to-bottom with L0 last (hidden projects are omitted, so no\n * stray rank=same name is emitted for an absent node). LevelBandLayout turns these into the\n * rank sets and the invisible chain that pins them — see graph-level-bands.ts for why the\n * chain is required at all.\n */\n private levelBands(graph: EnhancedGraph): LevelBand[] {\n const byLevel = new Map<number, string[]>();\n for (const project of Object.keys(graph)) {\n if (this.isHidden(graph[project])) continue;\n const level = graph[project].level;\n const nodeIds = byLevel.get(level);\n if (nodeIds === undefined) byLevel.set(level, [this.names.getNodeId(project)]);\n else nodeIds.push(this.names.getNodeId(project));\n }\n const levels = [...byLevel.keys()].sort((a: number, b: number): number => b - a);\n return levels.map(\n (level: number): LevelBand =>\n new LevelBand(level, [...(byLevel.get(level) as string[])].sort()),\n );\n }\n\n // Node lines: one statement per color mode (graph-color-modes.ts) — the label is the short\n // name plus a short meta line, because the fill now shows what the env list used to spell out.\n // No node carries a URL: EVERY box is clickable and opens the floating node menu instead, which\n // is where a design page is reached (see designLinks).\n private dotNodes(graph: EnhancedGraph, model: GraphRenderModel, palette: ProductPalette): string {\n let dot = '';\n for (const project of Object.keys(graph)) {\n const info = graph[project];\n if (this.isHidden(info)) continue;\n // Identity is the project key; the LABEL is the pretty short name.\n const facts = new NodeFacts(\n this.names.getNodeId(project),\n this.names.getShortName(project),\n info.level,\n info.role ?? 'lib',\n info.framework ?? [],\n info.products ?? [],\n );\n this.styler.record(model.legend, facts, palette);\n dot += model.styledNode(facts, this.styler.dots(facts, palette));\n }\n return dot;\n }\n\n // Edge lines (dependencies). An edge to an api-lib is styled by WHY it exists\n // (implements/uses/uses-implements, from apiRelations); every other dependency\n // keeps the default plain arrow. In the Product color mode an edge crossing into another\n // product is ALSO dashed in that product's color (#1204), so product boundaries read at a glance.\n private dotEdges(graph: EnhancedGraph, model: GraphRenderModel, palette: ProductPalette): string {\n let dot = '';\n for (const project of Object.keys(graph)) {\n const info = graph[project];\n if (this.isHidden(info)) continue;\n const nodeId = this.names.getNodeId(project);\n for (const dep of info.dependsOn || []) {\n // Both endpoints must be visible — an edge to/from a hidden box\n // is dropped so no connection dangles into empty space.\n if (graph[dep] !== undefined && this.isHidden(graph[dep])) continue;\n dot += model.edge(\n nodeId,\n this.names.getNodeId(dep),\n this.edgeDot(nodeId, this.names.getNodeId(dep), info.apiRelations?.[dep]),\n this.crossProductAttrs(info.products ?? [], graph[dep]?.products ?? [], model, palette),\n );\n }\n }\n return dot;\n }\n\n /**\n * The Product color mode's extra attributes for one dependency: dashed, thicker and in the color\n * of the product it crosses into, or '' for an edge that stays inside its source's products.\n */\n private crossProductAttrs(\n from: readonly string[],\n to: readonly string[],\n model: GraphRenderModel,\n palette: ProductPalette,\n ): string {\n const into = this.boundary.crossedInto(from, to);\n if (into === null) return '';\n model.legend.crossProductEdges++;\n return `style=dashed, color=\"${palette.colorOf(into).color}\", penwidth=2`;\n }\n\n /**\n * Generate the interactive page: the drawer shell around a viz.js-rendered graph.\n *\n * The Impact sidecar is a plain `<script src>` loaded BEFORE the page scripts, so the page knows\n * the branch's impact when it first draws. It is per-branch and gitignored (graph-impact.ts):\n * when it is absent the browser skips it and Impact is disabled with its reason.\n */\n generateHTML(\n model: GraphRenderModel,\n links: DesignLink[],\n title: string = 'Monorepo Dependency Architecture',\n lockControl: string = '',\n responsibilitiesHtml: string = '',\n ): string {\n const parts = new ShellParts(\n title,\n lockControl,\n this.legend.sections(model.legend),\n this.legend.edgeKey(),\n this.filterAssets.html(),\n this.snapshot.html(),\n responsibilitiesHtml,\n model.legend.palette.colors,\n );\n return `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>${title}</title>\n <script src=\"https://cdn.jsdelivr.net/npm/@viz-js/viz@3.28.0/dist/viz-global.js\"></script>\n <script src=\"${IMPACT_SIDECAR_SRC}\"></script>\n <style>${this.styles()}</style>\n</head>\n<body>\n ${this.shell.body(parts)}\n <script>${this.nodeMenu.script()}</script>\n <script>${this.filterJs()}</script>\n <script>${this.navigation.script()}</script>\n <script>${this.script(model, links)}</script>\n</body>\n</html>`;\n }\n\n /** Shared menu/dim/filter/zoom rules first, then the page's own, so its `#graph` rules win. */\n private styles(): string {\n return (\n this.nodeMenu.styles() +\n this.nodeMenu.dimStyles('#graph') +\n this.filterAssets.styles() +\n this.navigation.styles() +\n this.pageStyles.css()\n );\n }\n\n /**\n * The drawer's type-to-search lock field, replacing a `<select>` that listed every project and\n * was unusable at hundreds of options. Picking a project LOCKS the graph into that box's hover\n * view — its full ancestor + descendant chain stays lit while everything else dims — and narrows\n * the responsibilities panel to that chain. Clearing the field, or Esc, unlocks.\n *\n * Each option's VALUE is the node id the SVG is keyed on; its label is the level and short name.\n * Options are ordered by level DESCENDING to match the responsibilities cards.\n */\n lockControl(graph: EnhancedGraph): string {\n const projects = Object.keys(graph);\n projects.sort((a: string, b: string): number => {\n const levelDiff = graph[b].level - graph[a].level;\n if (levelDiff !== 0) return levelDiff;\n return a.localeCompare(b);\n });\n let options = '';\n for (const project of projects) {\n if (this.isHidden(graph[project])) continue;\n const nodeId = this.escapeHtml(this.names.getNodeId(project));\n const shortName = this.escapeHtml(this.names.getShortName(project));\n options += `<option value=\"${nodeId}\">L${graph[project].level} · ${shortName}</option>`;\n }\n return (\n '<input type=\"search\" id=\"wp-lock\" list=\"wp-lock-options\" placeholder=\"Lock a project… ( / )\" ' +\n 'autocomplete=\"off\" spellcheck=\"false\">' +\n `<datalist id=\"wp-lock-options\">${options}</datalist>`\n );\n }\n\n private escapeHtml(text: string): string {\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n }\n\n /**\n * The page script. The browser code lives in graph-visualizer.client.ts — real, linted TypeScript\n * that tsc compiles in place, so what this inlines is its COMPILED .js sitting beside this file.\n *\n * The substitution is a blind split/join, which is why the placeholder token must appear EXACTLY\n * ONCE in the client (never in one of its comments): every literal occurrence would otherwise be\n * replaced by the whole DOT.\n */\n private script(model: GraphRenderModel, links: DesignLink[]): string {\n return this.clientJs()\n .split(CLIENT_MODEL_PLACEHOLDER)\n .join(this.filterAssets.json(model))\n .split(CLIENT_DESIGN_LINKS_PLACEHOLDER)\n .join(this.filterAssets.json(links));\n }\n\n /**\n * Write the committed architecture visualization to\n * architecture/dependencies.html, next to dependencies.json.\n *\n * This is a checked-in artifact, regenerated deterministically by\n * architecture:generate so every box keeps its menu, and the \"View Design\"\n * item keeps pointing at each project's committed design.html as designs\n * come and go. The DOT is embedded in the HTML (rendered client-side by\n * viz.js). Output is deterministic (sorted graph in → same bytes out) so git\n * only shows a diff when the architecture actually changed.\n *\n * `productDependencies` is the `product-tags` rule's matrix, listed in the Product legend; null\n * when the rule is OFF, and the legend then lists no matrix.\n */\n writeVisualization(\n graph: EnhancedGraph,\n workspaceRoot: string,\n productDependencies: ProductDependencyMatrix | null,\n title: string = 'Monorepo Dependency Architecture',\n ): VisualizationPaths {\n const outputDir = path.join(workspaceRoot, ARCH_OUTPUT_DIR);\n\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n const lockControl = this.lockControl(graph);\n const responsibilities = this.responsibilities.generateSection(graph, workspaceRoot);\n const model = this.generateRenderModel(graph, title);\n model.legend.productDependencies = productDependencies === null ? null : [...productDependencies.entries];\n const html = this.generateHTML(\n model,\n this.designLinks(graph),\n title,\n lockControl,\n responsibilities,\n );\n const htmlPath = path.join(outputDir, 'dependencies.html');\n fs.writeFileSync(htmlPath, html, 'utf-8');\n\n return new VisualizationPaths(htmlPath);\n }\n\n /**\n * Open the HTML visualization in the default browser\n */\n openVisualization(htmlPath: string): boolean {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const platform = process.platform;\n let openCommand: string;\n\n if (platform === 'darwin') {\n openCommand = `open \"${htmlPath}\"`;\n } else if (platform === 'win32') {\n openCommand = `start \"\" \"${htmlPath}\"`;\n } else {\n openCommand = `xdg-open \"${htmlPath}\"`;\n }\n\n execSync(openCommand, { stdio: 'ignore' });\n return true;\n } catch (err: unknown) {\n const error = toError(err);\n console.warn(`⚠️ Could not open browser: ${error.message}`);\n return false;\n }\n }\n}\n"]}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Goal vs Current (#1239): turns the semantic diff of the two saved runtime files into the overlay the
3
+ * runtime viewer's "Goal vs Current" color mode draws.
4
+ *
5
+ * The overlay is rendered by the SAME shared runtime renderer as both pages (generateRuntimeRenderModel
6
+ * over RuntimeUnionGraph), so queue boxes, self-queue sub-rows, level bands and non-constraining
7
+ * feedback edges behave exactly as on the normal pages. Only the statements are restyled afterwards:
8
+ *
9
+ * added in goal green
10
+ * removed from goal red, dashed box / dotted arrow — still drawn, never dropped
11
+ * changed amber; a moved level reads `L4 → L2`
12
+ * unchanged subdued grey, kept for context
13
+ *
14
+ * Every drawn box and arrow maps back to the diff's FACT identities (never to display names or edge
15
+ * ids), and its before/after lines travel in the page for the details panel.
16
+ */
17
+ import { RenderEdge, RenderNode, RuntimeComparisonView } from './graph-render-model';
18
+ import type { RuntimeGraph } from './runtime-graph-model';
19
+ import { RuntimeDiffStatus, RuntimeFactChange } from './runtime-graph-diff';
20
+ import { RuntimeVizOptions } from './runtime-viz-options';
21
+ /** Render-node / render-edge → the diff fact identities it draws. */
22
+ export declare class RuntimeComparisonIds {
23
+ private readonly graph;
24
+ private readonly byNode;
25
+ private readonly triggerService;
26
+ constructor(graph: RuntimeGraph);
27
+ node(node: RenderNode): string[];
28
+ edge(edge: RenderEdge, nodes: Map<string, RenderNode>): string[];
29
+ /** A service's arrow into a context node: an external system, a remote service or a vendor library. */
30
+ private towards;
31
+ private queues;
32
+ private put;
33
+ }
34
+ /** Restyles one rendered statement for its diff status. */
35
+ export declare class RuntimeComparisonStyler {
36
+ status(changes: RuntimeFactChange[]): RuntimeDiffStatus;
37
+ /** A service box: rebuilt (its HTML label carries the level badge and the status in words). */
38
+ service(node: RenderNode, status: RuntimeDiffStatus, changes: RuntimeFactChange[]): string;
39
+ /** A context box (queue, datastore, clock, vendor): kind shape kept, status colors laid over it. */
40
+ context(node: RenderNode, status: RuntimeDiffStatus, changes: RuntimeFactChange[]): string;
41
+ /** An arrow: its line style says rpc/event as always; color (and dots for a removal) says the diff. */
42
+ edge(dot: string, status: RuntimeDiffStatus): string;
43
+ /** `L4`, or `L4 → L2` when the level moved. */
44
+ levels(change: RuntimeFactChange | undefined): string;
45
+ }
46
+ /** Builds the Goal vs Current view both runtime pages carry. */
47
+ export declare class RuntimeGoalComparison {
48
+ private readonly styler;
49
+ build(current: RuntimeGraph, goal: RuntimeGraph, options: RuntimeVizOptions): RuntimeComparisonView;
50
+ private restyleNodes;
51
+ private restyleEdges;
52
+ private changes;
53
+ private summary;
54
+ private line;
55
+ }
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ /**
3
+ * Goal vs Current (#1239): turns the semantic diff of the two saved runtime files into the overlay the
4
+ * runtime viewer's "Goal vs Current" color mode draws.
5
+ *
6
+ * The overlay is rendered by the SAME shared runtime renderer as both pages (generateRuntimeRenderModel
7
+ * over RuntimeUnionGraph), so queue boxes, self-queue sub-rows, level bands and non-constraining
8
+ * feedback edges behave exactly as on the normal pages. Only the statements are restyled afterwards:
9
+ *
10
+ * added in goal green
11
+ * removed from goal red, dashed box / dotted arrow — still drawn, never dropped
12
+ * changed amber; a moved level reads `L4 → L2`
13
+ * unchanged subdued grey, kept for context
14
+ *
15
+ * Every drawn box and arrow maps back to the diff's FACT identities (never to display names or edge
16
+ * ids), and its before/after lines travel in the page for the details panel.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.RuntimeGoalComparison = exports.RuntimeComparisonStyler = exports.RuntimeComparisonIds = void 0;
20
+ const dot_syntax_1 = require("./dot-syntax");
21
+ const graph_render_model_1 = require("./graph-render-model");
22
+ const runtime_graph_diff_1 = require("./runtime-graph-diff");
23
+ const runtime_union_graph_1 = require("./runtime-union-graph");
24
+ const runtime_viz_options_1 = require("./runtime-viz-options");
25
+ const runtime_visualizer_1 = require("./runtime-visualizer");
26
+ const runtime_layout_1 = require("./runtime-layout");
27
+ const remote_service_node_id_1 = require("./remote-service-node-id");
28
+ const runtime_external_triggers_1 = require("./runtime-external-triggers");
29
+ const runtime_goal_styles_1 = require("./runtime-goal-styles");
30
+ /** Render-node / render-edge → the diff fact identities it draws. */
31
+ class RuntimeComparisonIds {
32
+ graph;
33
+ byNode = new Map();
34
+ triggerService = new Map();
35
+ constructor(graph) {
36
+ this.graph = graph;
37
+ const safe = (raw) => raw.replace(/[^A-Za-z0-9_]/g, '_');
38
+ for (const name of Object.keys(graph.services))
39
+ this.put(name, `service:${name}`);
40
+ for (const id of Object.keys(graph.externalSystems ?? {}))
41
+ this.put(`system__${safe(id)}`, `external-system:${id}`);
42
+ for (const name of Object.keys(graph.remoteServices ?? {}))
43
+ this.put(new remote_service_node_id_1.RemoteServiceNodeId().of(name), `remote-service:${name}`);
44
+ for (const use of graph.unresolvedUses) {
45
+ const owner = graph.apis[use.api]?.owner ?? use.api;
46
+ if (graph.apis[use.api]?.externalSystem === undefined)
47
+ this.put(`external__${owner}`, `external-library:${owner}`);
48
+ }
49
+ for (const trigger of graph.triggers) {
50
+ const id = `trigger:${trigger.kind}:${trigger.api}.${trigger.method}@${trigger.service}`;
51
+ this.triggerService.set(id, trigger.service);
52
+ if (trigger.kind === 'cron')
53
+ this.put(`cron__${safe(`${trigger.api}_${trigger.method}`)}`, id);
54
+ }
55
+ for (const group of new runtime_external_triggers_1.RuntimeExternalTriggers(graph.triggers).groups) {
56
+ for (const trigger of group.triggers)
57
+ this.put(group.from, `trigger:external:${trigger.api}.${trigger.method}@${trigger.service}`);
58
+ }
59
+ }
60
+ node(node) {
61
+ if (node.queueKeys.length > 0)
62
+ return this.queues(node);
63
+ return this.byNode.get(node.id) ?? [];
64
+ }
65
+ edge(edge, nodes) {
66
+ const from = nodes.get(edge.from);
67
+ const to = nodes.get(edge.to);
68
+ if (from !== undefined && from.queueKeys.length > 0)
69
+ return this.queues(from).map((queue) => `deliver:${queue}->${edge.to}`);
70
+ if (to !== undefined && to.queueKeys.length > 0)
71
+ return this.queues(to).map((queue) => `enqueue:${edge.from}->${queue}`);
72
+ if (this.graph.services[edge.from] === undefined)
73
+ return (this.byNode.get(edge.from) ?? []).filter((id) => this.triggerService.get(id) === edge.to);
74
+ if (this.graph.services[edge.to] !== undefined)
75
+ return [`rpc:${edge.from}->${edge.to}`];
76
+ return (this.byNode.get(edge.to) ?? []).flatMap((target) => this.towards(edge, target));
77
+ }
78
+ /** A service's arrow into a context node: an external system, a remote service or a vendor library. */
79
+ towards(edge, target) {
80
+ if (target.startsWith('external-system:'))
81
+ return [`external-use:${edge.from}->${target}`];
82
+ if (target.startsWith('remote-service:'))
83
+ return [`remote-call:${edge.from}->${target}#${edge.dot.includes('enqueue') ? 'pubsub' : 'rpc'}`];
84
+ const owner = target.slice('external-library:'.length);
85
+ return this.graph.unresolvedUses
86
+ .filter((use) => use.service === edge.from && (this.graph.apis[use.api]?.owner ?? use.api) === owner)
87
+ .map((use) => `unresolved-use:${use.service}->${use.api}`);
88
+ }
89
+ queues(node) {
90
+ return node.queueKeys.map((key) => (key.startsWith('queue:') ? `contract-queue:${key.slice(6)}` : `queue:${key}`));
91
+ }
92
+ put(renderId, factId) {
93
+ if (!this.byNode.has(renderId))
94
+ this.byNode.set(renderId, []);
95
+ if (!this.byNode.get(renderId).includes(factId))
96
+ this.byNode.get(renderId).push(factId);
97
+ }
98
+ }
99
+ exports.RuntimeComparisonIds = RuntimeComparisonIds;
100
+ /** Restyles one rendered statement for its diff status. */
101
+ class RuntimeComparisonStyler {
102
+ status(changes) {
103
+ const statuses = new Set(changes.map((change) => change.status));
104
+ if (statuses.size === 0)
105
+ return runtime_graph_diff_1.RuntimeDiffStatus.UNCHANGED;
106
+ if (statuses.size === 1)
107
+ return [...statuses][0];
108
+ return runtime_graph_diff_1.RuntimeDiffStatus.CHANGED;
109
+ }
110
+ /** A service box: rebuilt (its HTML label carries the level badge and the status in words). */
111
+ service(node, status, changes) {
112
+ const style = runtime_goal_styles_1.DIFF_STYLES[status];
113
+ const change = changes[0];
114
+ const level = this.levels(change);
115
+ const changed = status === runtime_graph_diff_1.RuntimeDiffStatus.CHANGED && change !== undefined ? `: ${change.changedFields.join(', ')}` : '';
116
+ const label = `<FONT COLOR="${style.text}99">${(0, dot_syntax_1.htmlLabelText)(level)}</FONT>&#160;&#160;<B>${(0, dot_syntax_1.htmlLabelText)(node.id.split('/').pop() ?? node.id)}</B>` +
117
+ `<BR/>${(0, dot_syntax_1.htmlLabelText)(node.tags?.role ?? 'unknown')}<BR/>${(0, dot_syntax_1.htmlLabelText)(`${style.word}${changed}`)}`;
118
+ const boxStyle = status === runtime_graph_diff_1.RuntimeDiffStatus.REMOVED ? 'filled,rounded,dashed' : 'filled,rounded';
119
+ return (` "${(0, dot_syntax_1.dotValue)(node.id)}" [style="${boxStyle}", fillcolor="${style.fill}", color="${style.border}", ` +
120
+ `penwidth=2, fontcolor="${style.text}", label=<${label}>];\n`);
121
+ }
122
+ /** A context box (queue, datastore, clock, vendor): kind shape kept, status colors laid over it. */
123
+ context(node, status, changes) {
124
+ const style = runtime_goal_styles_1.DIFF_STYLES[status];
125
+ let dot = node.dot;
126
+ const moved = changes.find((change) => change.changedFields.includes('level'));
127
+ if (node.queueKeys.length > 0 && moved !== undefined)
128
+ dot = dot.replace(/(label=" \|)L\d+ {2}/, `$1${this.levels(moved).replace(/>/g, '\\>')} `);
129
+ const base = /style="([^"]*)"/.exec(dot)?.[1] ?? 'filled';
130
+ const boxStyle = status === runtime_graph_diff_1.RuntimeDiffStatus.REMOVED && !base.includes('dashed') ? `${base},dashed` : base;
131
+ return `${dot.slice(0, -2)} [style="${boxStyle}", fillcolor="${style.fill}", color="${style.border}", penwidth=2, fontcolor="${style.text}"];\n`;
132
+ }
133
+ /** An arrow: its line style says rpc/event as always; color (and dots for a removal) says the diff. */
134
+ edge(dot, status) {
135
+ const style = runtime_goal_styles_1.DIFF_STYLES[status];
136
+ const removed = status === runtime_graph_diff_1.RuntimeDiffStatus.REMOVED ? ', style=dotted' : '';
137
+ const width = status === runtime_graph_diff_1.RuntimeDiffStatus.UNCHANGED ? 1 : 2.2;
138
+ return `${dot.slice(0, -2)} [color="${style.border}", fontcolor="${style.border}", penwidth=${width}${removed}];\n`;
139
+ }
140
+ /** `L4`, or `L4 → L2` when the level moved. */
141
+ levels(change) {
142
+ const before = change?.before?.['level'];
143
+ const after = change?.after?.['level'];
144
+ if (before !== undefined && after !== undefined && before !== after)
145
+ return `${before} → ${after}`;
146
+ return after ?? before ?? '';
147
+ }
148
+ }
149
+ exports.RuntimeComparisonStyler = RuntimeComparisonStyler;
150
+ /** Builds the Goal vs Current view both runtime pages carry. */
151
+ class RuntimeGoalComparison {
152
+ styler = new RuntimeComparisonStyler();
153
+ build(current, goal, options) {
154
+ const diff = new runtime_graph_diff_1.RuntimeGraphDiff().compare(current, goal);
155
+ const union = new runtime_union_graph_1.RuntimeUnionGraph().build(current, goal);
156
+ const tags = {};
157
+ for (const key of Object.keys(union.queues))
158
+ tags[key] = diff.get(`queue:${key}`)?.status ?? '';
159
+ const model = (0, runtime_visualizer_1.generateRuntimeRenderModel)(union, 'Goal vs Current', options.withPage(runtime_viz_options_1.RuntimePageKind.COMPARISON, tags));
160
+ const nodeDetails = {};
161
+ const edgeDetails = {};
162
+ const ids = new RuntimeComparisonIds(union);
163
+ this.restyleNodes(model, ids, diff, nodeDetails);
164
+ this.restyleEdges(model, ids, diff, edgeDetails);
165
+ model.fullDot = new runtime_layout_1.RuntimeLayout().assemble(model);
166
+ (0, dot_syntax_1.assertValidDot)(model.fullDot, 'runtime-architecture goal comparison');
167
+ return new graph_render_model_1.RuntimeComparisonView(true, '', 'Current → Goal', this.summary(diff), model, nodeDetails, edgeDetails, diff.differences().map((change) => this.line(change)));
168
+ }
169
+ restyleNodes(model, ids, diff, details) {
170
+ for (let index = 0; index < model.nodes.length; index++) {
171
+ const node = model.nodes[index];
172
+ const changes = this.changes(ids.node(node), diff);
173
+ const status = this.styler.status(changes);
174
+ const dot = node.tags !== null ? this.styler.service(node, status, changes) : this.styler.context(node, status, changes);
175
+ model.nodes[index] = new graph_render_model_1.RenderNode(node.id, dot, null, node.tags, node.products, node.queueKeys);
176
+ details[node.id] = changes.flatMap((change) => change.lines());
177
+ }
178
+ }
179
+ restyleEdges(model, ids, diff, details) {
180
+ const nodes = new Map();
181
+ for (const node of model.nodes)
182
+ nodes.set(node.id, node);
183
+ for (let index = 0; index < model.edges.length; index++) {
184
+ const edge = model.edges[index];
185
+ const changes = this.changes(ids.edge(edge, nodes), diff);
186
+ const status = this.styler.status(changes);
187
+ model.edges[index] = new graph_render_model_1.RenderEdge(edge.from, edge.to, this.styler.edge(edge.dot, status), edge.id, null);
188
+ details[edge.id] = [`${edge.from} → ${edge.to}`, ...changes.flatMap((change) => change.lines())];
189
+ }
190
+ }
191
+ changes(factIds, diff) {
192
+ return factIds
193
+ .map((id) => diff.get(id))
194
+ .filter((change) => change !== undefined);
195
+ }
196
+ summary(diff) {
197
+ if (diff.identical())
198
+ return 'No differences: the goal matches the current runtime graph.';
199
+ const counts = diff.counts();
200
+ const levels = diff.maxLevelBefore === diff.maxLevelAfter ? '' : ` · max level L${diff.maxLevelBefore} → L${diff.maxLevelAfter}`;
201
+ return `${counts.added} added · ${counts.removed} removed · ${counts.changed} changed · ${counts.unchanged} unchanged${levels}`;
202
+ }
203
+ line(change) {
204
+ const fields = change.status === runtime_graph_diff_1.RuntimeDiffStatus.CHANGED ? ` (${change.changedFields.join(', ')})` : '';
205
+ return `${change.status}: ${change.label}${fields}`;
206
+ }
207
+ }
208
+ exports.RuntimeGoalComparison = RuntimeGoalComparison;
209
+ //# sourceMappingURL=runtime-goal-comparison.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-goal-comparison.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-goal-comparison.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Goal vs Current (#1239): turns the semantic diff of the two saved runtime files into the overlay the\n * runtime viewer's \"Goal vs Current\" color mode draws.\n *\n * The overlay is rendered by the SAME shared runtime renderer as both pages (generateRuntimeRenderModel\n * over RuntimeUnionGraph), so queue boxes, self-queue sub-rows, level bands and non-constraining\n * feedback edges behave exactly as on the normal pages. Only the statements are restyled afterwards:\n *\n * added in goal green\n * removed from goal red, dashed box / dotted arrow — still drawn, never dropped\n * changed amber; a moved level reads `L4 → L2`\n * unchanged subdued grey, kept for context\n *\n * Every drawn box and arrow maps back to the diff's FACT identities (never to display names or edge\n * ids), and its before/after lines travel in the page for the details panel.\n */\n\nimport { dotValue, htmlLabelText, assertValidDot } from './dot-syntax';\nimport { GraphRenderModel, RenderEdge, RenderNode, RuntimeComparisonView } from './graph-render-model';\nimport type { RuntimeGraph, RuntimeUnresolved } from './runtime-graph-model';\nimport { RuntimeGraphDiff, RuntimeDiffStatus, RuntimeFactChange, RuntimeGraphDiffResult } from './runtime-graph-diff';\nimport { RuntimeUnionGraph } from './runtime-union-graph';\nimport { RuntimeVizOptions, RuntimePageKind } from './runtime-viz-options';\nimport { generateRuntimeRenderModel } from './runtime-visualizer';\nimport { RuntimeLayout } from './runtime-layout';\nimport { RemoteServiceNodeId } from './remote-service-node-id';\nimport { RuntimeExternalTriggers } from './runtime-external-triggers';\nimport { DIFF_STYLES } from './runtime-goal-styles';\n\n/** Render-node / render-edge → the diff fact identities it draws. */\nexport class RuntimeComparisonIds {\n private readonly byNode = new Map<string, string[]>();\n private readonly triggerService = new Map<string, string>();\n\n constructor(private readonly graph: RuntimeGraph) {\n const safe = (raw: string): string => raw.replace(/[^A-Za-z0-9_]/g, '_');\n for (const name of Object.keys(graph.services)) this.put(name, `service:${name}`);\n for (const id of Object.keys(graph.externalSystems ?? {})) this.put(`system__${safe(id)}`, `external-system:${id}`);\n for (const name of Object.keys(graph.remoteServices ?? {})) this.put(new RemoteServiceNodeId().of(name), `remote-service:${name}`);\n for (const use of graph.unresolvedUses) {\n const owner = graph.apis[use.api]?.owner ?? use.api;\n if (graph.apis[use.api]?.externalSystem === undefined) this.put(`external__${owner}`, `external-library:${owner}`);\n }\n for (const trigger of graph.triggers) {\n const id = `trigger:${trigger.kind}:${trigger.api}.${trigger.method}@${trigger.service}`;\n this.triggerService.set(id, trigger.service);\n if (trigger.kind === 'cron') this.put(`cron__${safe(`${trigger.api}_${trigger.method}`)}`, id);\n }\n for (const group of new RuntimeExternalTriggers(graph.triggers).groups) {\n for (const trigger of group.triggers) this.put(group.from, `trigger:external:${trigger.api}.${trigger.method}@${trigger.service}`);\n }\n }\n\n node(node: RenderNode): string[] {\n if (node.queueKeys.length > 0) return this.queues(node);\n return this.byNode.get(node.id) ?? [];\n }\n\n edge(edge: RenderEdge, nodes: Map<string, RenderNode>): string[] {\n const from = nodes.get(edge.from);\n const to = nodes.get(edge.to);\n if (from !== undefined && from.queueKeys.length > 0) return this.queues(from).map((queue: string) => `deliver:${queue}->${edge.to}`);\n if (to !== undefined && to.queueKeys.length > 0) return this.queues(to).map((queue: string) => `enqueue:${edge.from}->${queue}`);\n if (this.graph.services[edge.from] === undefined)\n return (this.byNode.get(edge.from) ?? []).filter((id: string) => this.triggerService.get(id) === edge.to);\n if (this.graph.services[edge.to] !== undefined) return [`rpc:${edge.from}->${edge.to}`];\n return (this.byNode.get(edge.to) ?? []).flatMap((target: string) => this.towards(edge, target));\n }\n\n /** A service's arrow into a context node: an external system, a remote service or a vendor library. */\n private towards(edge: RenderEdge, target: string): string[] {\n if (target.startsWith('external-system:')) return [`external-use:${edge.from}->${target}`];\n if (target.startsWith('remote-service:'))\n return [`remote-call:${edge.from}->${target}#${edge.dot.includes('enqueue') ? 'pubsub' : 'rpc'}`];\n const owner = target.slice('external-library:'.length);\n return this.graph.unresolvedUses\n .filter((use: RuntimeUnresolved) => use.service === edge.from && (this.graph.apis[use.api]?.owner ?? use.api) === owner)\n .map((use: RuntimeUnresolved) => `unresolved-use:${use.service}->${use.api}`);\n }\n\n private queues(node: RenderNode): string[] {\n return node.queueKeys.map((key: string) => (key.startsWith('queue:') ? `contract-queue:${key.slice(6)}` : `queue:${key}`));\n }\n\n private put(renderId: string, factId: string): void {\n if (!this.byNode.has(renderId)) this.byNode.set(renderId, []);\n if (!this.byNode.get(renderId)!.includes(factId)) this.byNode.get(renderId)!.push(factId);\n }\n}\n\n/** Restyles one rendered statement for its diff status. */\nexport class RuntimeComparisonStyler {\n status(changes: RuntimeFactChange[]): RuntimeDiffStatus {\n const statuses = new Set(changes.map((change: RuntimeFactChange) => change.status));\n if (statuses.size === 0) return RuntimeDiffStatus.UNCHANGED;\n if (statuses.size === 1) return [...statuses][0];\n return RuntimeDiffStatus.CHANGED;\n }\n\n /** A service box: rebuilt (its HTML label carries the level badge and the status in words). */\n service(node: RenderNode, status: RuntimeDiffStatus, changes: RuntimeFactChange[]): string {\n const style = DIFF_STYLES[status];\n const change = changes[0];\n const level = this.levels(change);\n const changed = status === RuntimeDiffStatus.CHANGED && change !== undefined ? `: ${change.changedFields.join(', ')}` : '';\n const label =\n `<FONT COLOR=\"${style.text}99\">${htmlLabelText(level)}</FONT>&#160;&#160;<B>${htmlLabelText(node.id.split('/').pop() ?? node.id)}</B>` +\n `<BR/>${htmlLabelText(node.tags?.role ?? 'unknown')}<BR/>${htmlLabelText(`${style.word}${changed}`)}`;\n const boxStyle = status === RuntimeDiffStatus.REMOVED ? 'filled,rounded,dashed' : 'filled,rounded';\n return (\n ` \"${dotValue(node.id)}\" [style=\"${boxStyle}\", fillcolor=\"${style.fill}\", color=\"${style.border}\", ` +\n `penwidth=2, fontcolor=\"${style.text}\", label=<${label}>];\\n`\n );\n }\n\n /** A context box (queue, datastore, clock, vendor): kind shape kept, status colors laid over it. */\n context(node: RenderNode, status: RuntimeDiffStatus, changes: RuntimeFactChange[]): string {\n const style = DIFF_STYLES[status];\n let dot = node.dot;\n const moved = changes.find((change: RuntimeFactChange) => change.changedFields.includes('level'));\n if (node.queueKeys.length > 0 && moved !== undefined)\n dot = dot.replace(/(label=\" \\|)L\\d+ {2}/, `$1${this.levels(moved).replace(/>/g, '\\\\>')} `);\n const base = /style=\"([^\"]*)\"/.exec(dot)?.[1] ?? 'filled';\n const boxStyle = status === RuntimeDiffStatus.REMOVED && !base.includes('dashed') ? `${base},dashed` : base;\n return `${dot.slice(0, -2)} [style=\"${boxStyle}\", fillcolor=\"${style.fill}\", color=\"${style.border}\", penwidth=2, fontcolor=\"${style.text}\"];\\n`;\n }\n\n /** An arrow: its line style says rpc/event as always; color (and dots for a removal) says the diff. */\n edge(dot: string, status: RuntimeDiffStatus): string {\n const style = DIFF_STYLES[status];\n const removed = status === RuntimeDiffStatus.REMOVED ? ', style=dotted' : '';\n const width = status === RuntimeDiffStatus.UNCHANGED ? 1 : 2.2;\n return `${dot.slice(0, -2)} [color=\"${style.border}\", fontcolor=\"${style.border}\", penwidth=${width}${removed}];\\n`;\n }\n\n /** `L4`, or `L4 → L2` when the level moved. */\n levels(change: RuntimeFactChange | undefined): string {\n const before = change?.before?.['level'];\n const after = change?.after?.['level'];\n if (before !== undefined && after !== undefined && before !== after) return `${before} → ${after}`;\n return after ?? before ?? '';\n }\n}\n\n/** Builds the Goal vs Current view both runtime pages carry. */\nexport class RuntimeGoalComparison {\n private readonly styler = new RuntimeComparisonStyler();\n\n build(current: RuntimeGraph, goal: RuntimeGraph, options: RuntimeVizOptions): RuntimeComparisonView {\n const diff = new RuntimeGraphDiff().compare(current, goal);\n const union = new RuntimeUnionGraph().build(current, goal);\n const tags: Record<string, string> = {};\n for (const key of Object.keys(union.queues)) tags[key] = diff.get(`queue:${key}`)?.status ?? '';\n const model = generateRuntimeRenderModel(union, 'Goal vs Current', options.withPage(RuntimePageKind.COMPARISON, tags));\n const nodeDetails: Record<string, string[]> = {};\n const edgeDetails: Record<string, string[]> = {};\n const ids = new RuntimeComparisonIds(union);\n this.restyleNodes(model, ids, diff, nodeDetails);\n this.restyleEdges(model, ids, diff, edgeDetails);\n model.fullDot = new RuntimeLayout().assemble(model);\n assertValidDot(model.fullDot, 'runtime-architecture goal comparison');\n return new RuntimeComparisonView(\n true,\n '',\n 'Current → Goal',\n this.summary(diff),\n model,\n nodeDetails,\n edgeDetails,\n diff.differences().map((change: RuntimeFactChange) => this.line(change)),\n );\n }\n\n private restyleNodes(model: GraphRenderModel, ids: RuntimeComparisonIds, diff: RuntimeGraphDiffResult, details: Record<string, string[]>): void {\n for (let index = 0; index < model.nodes.length; index++) {\n const node = model.nodes[index];\n const changes = this.changes(ids.node(node), diff);\n const status = this.styler.status(changes);\n const dot = node.tags !== null ? this.styler.service(node, status, changes) : this.styler.context(node, status, changes);\n model.nodes[index] = new RenderNode(node.id, dot, null, node.tags, node.products, node.queueKeys);\n details[node.id] = changes.flatMap((change: RuntimeFactChange) => change.lines());\n }\n }\n\n private restyleEdges(model: GraphRenderModel, ids: RuntimeComparisonIds, diff: RuntimeGraphDiffResult, details: Record<string, string[]>): void {\n const nodes = new Map<string, RenderNode>();\n for (const node of model.nodes) nodes.set(node.id, node);\n for (let index = 0; index < model.edges.length; index++) {\n const edge = model.edges[index];\n const changes = this.changes(ids.edge(edge, nodes), diff);\n const status = this.styler.status(changes);\n model.edges[index] = new RenderEdge(edge.from, edge.to, this.styler.edge(edge.dot, status), edge.id, null);\n details[edge.id] = [`${edge.from} → ${edge.to}`, ...changes.flatMap((change: RuntimeFactChange) => change.lines())];\n }\n }\n\n private changes(factIds: string[], diff: RuntimeGraphDiffResult): RuntimeFactChange[] {\n return factIds\n .map((id: string) => diff.get(id))\n .filter((change: RuntimeFactChange | undefined): change is RuntimeFactChange => change !== undefined);\n }\n\n private summary(diff: RuntimeGraphDiffResult): string {\n if (diff.identical()) return 'No differences: the goal matches the current runtime graph.';\n const counts = diff.counts();\n const levels = diff.maxLevelBefore === diff.maxLevelAfter ? '' : ` · max level L${diff.maxLevelBefore} → L${diff.maxLevelAfter}`;\n return `${counts.added} added · ${counts.removed} removed · ${counts.changed} changed · ${counts.unchanged} unchanged${levels}`;\n }\n\n private line(change: RuntimeFactChange): string {\n const fields = change.status === RuntimeDiffStatus.CHANGED ? ` (${change.changedFields.join(', ')})` : '';\n return `${change.status}: ${change.label}${fields}`;\n }\n}\n"]}
@@ -0,0 +1,17 @@
1
+ import type { RuntimeComparisonView } from './graph-render-model';
2
+ /** The before/after lines the page's Goal vs Current details panel shows, keyed by overlay id. */
3
+ export declare class RuntimeGoalDetailsData {
4
+ readonly nodes: Record<string, string[]>;
5
+ readonly edges: Record<string, string[]>;
6
+ constructor(nodes: Record<string, string[]>, edges: Record<string, string[]>);
7
+ }
8
+ /**
9
+ * Goal vs Current details (#1239): the page script that opens before/after lines for a clicked box
10
+ * (a "Goal vs Current" item in the SHARED node menu) or a clicked arrow, while that mode is on.
11
+ * Inlined with toString, like RuntimeDetails, so the page works from `file://` with no fetch.
12
+ */
13
+ export declare class RuntimeGoalDetails {
14
+ private readonly comparison;
15
+ constructor(comparison: RuntimeComparisonView | null);
16
+ script(): string;
17
+ }