@webpieces/nx-webpieces-rules 0.4.910 → 0.4.912

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -33,13 +33,13 @@ It is wired into the build: the `@nx/js:tsc` target default lists it in
33
33
  ```json
34
34
  {
35
35
  "package": "@webpieces/nx-webpieces-rules",
36
- "config": ".webpieces/rules/nx.json"
36
+ "config": ".webpieces-config/rules/nx.json"
37
37
  }
38
38
  ```
39
39
 
40
40
  Keep the other selected owners and required root settings. Policy settings come
41
41
  from the declared owner file's direct policy-ID map. This entry belongs directly
42
- in `.webpieces/rules/nx.json` (an excerpt; the other owned policies also require
42
+ in `.webpieces-config/rules/nx.json` (an excerpt; the other owned policies also require
43
43
  explicit settings):
44
44
 
45
45
  ```json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/nx-webpieces-rules",
3
- "version": "0.4.910",
3
+ "version": "0.4.912",
4
4
  "description": "Nx-specific webpieces validation rules, graph tooling, executors, and inference plugin.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -20,12 +20,12 @@
20
20
  "README.md"
21
21
  ],
22
22
  "dependencies": {
23
- "@webpieces/api-doc-model": "0.4.910",
24
- "@webpieces/core-util": "0.4.910",
25
- "@webpieces/eslint-rules": "0.4.910",
26
- "@webpieces/rules-config": "0.4.910",
23
+ "@webpieces/api-doc-model": "0.4.912",
24
+ "@webpieces/core-util": "0.4.912",
25
+ "@webpieces/eslint-rules": "0.4.912",
26
+ "@webpieces/rules-config": "0.4.912",
27
27
  "madge": "8.0.0",
28
- "@webpieces/rules-sdk": "0.4.910"
28
+ "@webpieces/rules-sdk": "0.4.912"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@nx/devkit": ">=18.0.0"
@@ -41,7 +41,7 @@
41
41
  "access": "public"
42
42
  },
43
43
  "devDependencies": {
44
- "@webpieces/tooling-testkit": "0.4.910"
44
+ "@webpieces/tooling-testkit": "0.4.912"
45
45
  },
46
46
  "types": "./src/index.d.ts",
47
47
  "bin": {
@@ -24,7 +24,7 @@ const rule_gate_1 = require("../../lib/rule-gate");
24
24
  const toError_1 = require("../../toError");
25
25
  const TMP_MD_FILE = 'webpieces.dependencies.md';
26
26
  /**
27
- * Write the instructions documentation to .webpieces/instruct-ai/.
27
+ * Write the instructions documentation to .webpieces-logs/instruct-ai/.
28
28
  * Sourced from @webpieces/rules-config.
29
29
  */
30
30
  function writeTmpInstructionsFile(workspaceRoot) {
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-architecture-unchanged/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Architecture Unchanged Executor\n *\n * Validates that the current architecture graph matches the saved blessed graph.\n * This ensures no unapproved architecture changes have been made.\n *\n * Usage:\n * nx run architecture:validate-architecture-unchanged\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport {\n writeTemplate,\n Option,\n RuleFailError,\n renderRuleFailForHuman,\n} from '@webpieces/rules-config';\nimport { generateReducedGraph } from '../../lib/graph-generator';\nimport { sortGraphTopologically } from '../../lib/graph-sorter';\nimport { compareGraphs } from '../../lib/graph-comparator';\nimport { loadBlessedGraph, graphFileExists } from '../../lib/graph-loader';\nimport type { DependenciesFile } from '../../lib/graph-loader';\nimport { collectProjectInfo, enrichGraph, MetadataValidationError } from '../../lib/graph-metadata';\nimport { TagTruthCheck } from '../../lib/tag-truth';\nimport { ApprovedWiringGraph } from '../../lib/runtime-wiring/approved-graph';\nimport type { ExternalSystemDecls } from '../../lib/api-usage/api-relations';\nimport { ApiContractFiles } from '../../lib/api-contract-files';\nimport type { ApiContractFileRefs } from '../../lib/api-contract-files';\nimport type { RemoteServices } from '../../lib/remote-services';\nimport { RuleGate } from '../../lib/rule-gate';\nimport type { EnhancedGraph } from '../../lib/graph-sorter';\nimport { toError } from '../../toError';\n\nexport interface ValidateArchitectureUnchangedOptions {\n graphPath?: string;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nconst TMP_MD_FILE = 'webpieces.dependencies.md';\n\n/**\n * Write the instructions documentation to .webpieces/instruct-ai/.\n * Sourced from @webpieces/rules-config.\n */\nfunction writeTmpInstructionsFile(workspaceRoot: string): string {\n const mdPath = writeTemplate(workspaceRoot, TMP_MD_FILE);\n\n return mdPath;\n}\n\n/**\n * Report a current-vs-saved graph mismatch and write the AI instructions file.\n */\nfunction reportMismatch(summary: string, workspaceRoot: string): void {\n const mdPath = writeTmpInstructionsFile(workspaceRoot);\n\n console.error('❌ Architecture has changed since last update!');\n console.error('\\nDifferences:');\n console.error(summary);\n console.error('');\n console.error('⚠️ *** Refer to ' + mdPath + ' for instructions on how to fix *** ⚠️');\n console.error('');\n console.error('To fix:');\n console.error(' 1. Review the changes above');\n console.error(\n ' 2. If intentional, ASK USER to run: nx run architecture:generate since this is a critical change',\n );\n console.error(' 3. Commit the updated architecture/dependencies.json');\n}\n\n/**\n * Which APIs dependencies.json links to a contract file, compared by LINK only — an added or removed\n * API. The endpoints inside `architecture/apis/<Api>.json` are deliberately NOT compared (#949): an\n * endpoint change must not fail this rule. Null when the links match.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches reportMismatch in this file\nfunction describeContractLinkDrift(\n current: ApiContractFileRefs,\n saved: ApiContractFileRefs,\n): string | null {\n const names = [...new Set([...Object.keys(current), ...Object.keys(saved)])].sort();\n const changes: string[] = [];\n for (const name of names) {\n const a = current[name];\n const b = saved[name];\n if (a === undefined)\n changes.push(` - ${name}: linked in dependencies.json but no longer in source`);\n else if (b === undefined)\n changes.push(` + ${name}: in source but not linked from dependencies.json`);\n else if (a !== b) changes.push(` ~ ${name}: contract file link changed (${b} -> ${a})`);\n }\n if (changes.length === 0) return null;\n return `apiContractFiles drift (${changes.length} api(s)):\\n${changes.join('\\n')}`;\n}\n\n/**\n * Drift in EITHER side table of dependencies.json — the api contract-file links or the\n * external-system declarations — or null when both match. The first difference found is reported;\n * fixing it is the same single command either way, so listing both adds noise rather than information.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches describeContractLinkDrift above\nexport function describeTableDrift(\n current: CurrentArchitecture,\n saved: DependenciesFile,\n): string | null {\n const linkDrift = describeContractLinkDrift(current.apiContractFiles, saved.apiContractFiles);\n if (linkDrift !== null) return linkDrift;\n const systemDrift = describeExternalSystemDrift(current.externalSystems, saved.externalSystems);\n if (systemDrift !== null) return systemDrift;\n return describeRemoteServiceDrift(current.remoteServices, saved.remoteServices);\n}\n\n/**\n * The same drift report for the reviewed remote services (#1203), or null when they match. The table\n * is approval metadata, so a difference means the file changed under the generated graph.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches describeContractLinkDrift above\nfunction describeRemoteServiceDrift(current: RemoteServices, saved: RemoteServices): string | null {\n const names = [...new Set([...Object.keys(current), ...Object.keys(saved)])].sort();\n const changes: string[] = [];\n for (const name of names) {\n const a = current[name];\n const b = saved[name];\n if (a === undefined) changes.push(` - ${name}: in dependencies.json but no longer approved`);\n else if (b === undefined) changes.push(` + ${name}: approved but missing from dependencies.json`);\n else if (JSON.stringify(a) !== JSON.stringify(b))\n changes.push(` ~ ${name}: label/implements changed`);\n }\n if (changes.length === 0) return null;\n return `remoteServices drift (${changes.length} service(s)):\\n${changes.join('\\n')}`;\n}\n\n/**\n * The same drift report for the declared external systems, or null when they match. Named per\n * system so the message points at the database that changed rather than dumping two JSON blobs.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches describeContractLinkDrift above\nfunction describeExternalSystemDrift(\n current: ExternalSystemDecls,\n saved: ExternalSystemDecls,\n): string | null {\n const names = [...new Set([...Object.keys(current), ...Object.keys(saved)])].sort();\n const changes: string[] = [];\n for (const name of names) {\n const a = current[name];\n const b = saved[name];\n if (a === undefined)\n changes.push(` - ${name}: in dependencies.json but no longer declared in source`);\n else if (b === undefined)\n changes.push(` + ${name}: declared in source but missing from dependencies.json`);\n else if (JSON.stringify(a) !== JSON.stringify(b))\n changes.push(` ~ ${name}: kind/label/declarers changed`);\n }\n if (changes.length === 0) return null;\n return `externalSystems drift (${changes.length} system(s)):\\n${changes.join('\\n')}`;\n}\n\n/**\n * Build the current dependency graph exactly as the generator does: reduce the nx\n * graph, sort into levels, enrich with metadata, and attach the derived\n * apiRelations — so this validator compares like-for-like against the committed file.\n */\nexport class CurrentGraphBuilder {\n async build(workspaceRoot: string, graphPath?: string): Promise<CurrentArchitecture> {\n console.log('📊 Generating current dependency graph...');\n const reducedGraph = await generateReducedGraph();\n console.log('🔄 Computing topological layers...');\n const currentGraph = sortGraphTopologically(reducedGraph);\n console.log('🏷️ Enriching graph with framework + responsibilities metadata...');\n const projectInfos = await collectProjectInfo();\n enrichGraph(currentGraph, projectInfos, workspaceRoot);\n new TagTruthCheck().assertTrue(currentGraph, projectInfos, workspaceRoot);\n new ApprovedWiringGraph().attach(workspaceRoot, currentGraph, projectInfos, graphPath);\n const saved = loadBlessedGraph(workspaceRoot, graphPath);\n if (saved === null)\n throw new RuleFailError(\n 'validate-runtime-architecture',\n 'Missing approved graph.',\n undefined,\n undefined,\n [\n new Option(\n 'Migrate src/wiring.ts and review runtime-deps.json and API contract approvals.',\n true,\n ),\n ],\n );\n return new CurrentArchitecture(\n currentGraph,\n saved.apiContractFiles,\n saved.externalSystems,\n saved.remoteServices,\n );\n }\n}\n\n/** The regenerated graph plus the tables beside it — everything dependencies.json holds. */\nexport class CurrentArchitecture {\n constructor(\n public readonly graph: EnhancedGraph,\n public readonly apiContractFiles: ApiContractFileRefs,\n public readonly externalSystems: ExternalSystemDecls,\n public readonly remoteServices: RemoteServices,\n ) {}\n}\n\n/** The bootstrap path: there is nothing to diff against yet, so say how to create it. */\n// webpieces-disable no-function-outside-class -- executor step helper, matches reportMismatch in this file\nfunction reportMissingGraph(): never {\n throw new RuleFailError(\n 'validate-runtime-architecture',\n 'Missing reviewed architecture/dependencies.json.',\n undefined,\n undefined,\n [\n new Option(\n 'Run owning API source build checks to emit contract candidates, review and copy them into architecture/apis/<ApiName>.json, and create dependencies.json with projects:{}, apiContractFiles:{\"<ApiName>\":\"apis/<ApiName>.json\"}, reviewed externalSystems, and (only when a uses targets a service outside this workspace) reviewed remoteServices. Approve tagged owners runtime-deps.json candidates, then run architecture:generate and review the resulting graph.',\n true,\n ),\n ],\n );\n}\n\nexport default async function runExecutor(\n options: ValidateArchitectureUnchangedOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n const graphPath = options.graphPath;\n const workspaceRoot = context.root;\n\n // Epoch-gateable: this rule diffs against the blessed architecture/dependencies.json, so\n // \"grandfather the current drift until <epoch>\" is meaningful — hence honorEpoch = true.\n if (new RuleGate().isDisabled(workspaceRoot, 'validate-architecture-unchanged', true)) {\n return { success: true };\n }\n\n console.log('\\n🔍 Validating Architecture Unchanged\\n');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Check if saved graph exists\n if (!graphFileExists(workspaceRoot, graphPath)) {\n reportMissingGraph();\n return { success: false };\n }\n\n // Steps 1-3: build + enrich + scan the current graph (same pipeline the\n // generator runs, so any drift is caught).\n const currentGraph = await new CurrentGraphBuilder().build(workspaceRoot, graphPath);\n\n // Step 4: Load saved graph\n console.log('📂 Loading saved graph...');\n const savedGraph = loadBlessedGraph(workspaceRoot, graphPath);\n\n if (!savedGraph) {\n console.error('❌ Could not load saved graph');\n return { success: false };\n }\n\n // Step 5: Compare graphs\n console.log('🔍 Comparing current graph to saved graph...');\n const comparison = compareGraphs(currentGraph.graph, savedGraph.projects);\n\n if (!comparison.identical) {\n reportMismatch(comparison.summary, workspaceRoot);\n return { success: false };\n }\n\n // Step 6: Compare the two side tables as well: which APIs are linked to a contract file, and\n // the external-system declarations. The endpoints inside architecture/apis/<Api>.json are\n // NOT compared — an endpoint change must never fail this rule (#949).\n const tableDrift = describeTableDrift(currentGraph, savedGraph);\n if (tableDrift !== null) {\n reportMismatch(tableDrift, workspaceRoot);\n return { success: false };\n }\n\n console.log('✅ Architecture unchanged - current graph matches saved graph');\n return { success: true };\n } catch (err: unknown) {\n const error = toError(err);\n // A RuleFailError (e.g. a dependencies.json still carrying the moved `apiContracts` key)\n // carries its cures in Option[]; render them rather than dropping them with `.message`.\n const rendered =\n error instanceof RuleFailError ? renderRuleFailForHuman(error) : error.message;\n console.error('❌ Architecture validation failed:', rendered);\n reportMetadataFailure(error, workspaceRoot);\n return { success: false };\n }\n}\n\n// webpieces-disable no-function-outside-class -- executor diagnostic formatting\nfunction reportMetadataFailure(error: Error, workspaceRoot: string): void {\n if (error instanceof MetadataValidationError) {\n const mdPath = writeTemplate(workspaceRoot, 'webpieces.responsibilities.md');\n console.error('');\n console.error(\n '⚠️ *** Refer to ' + mdPath + ' for how to author responsibilities.md files *** ⚠️',\n );\n }\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-architecture-unchanged/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Architecture Unchanged Executor\n *\n * Validates that the current architecture graph matches the saved blessed graph.\n * This ensures no unapproved architecture changes have been made.\n *\n * Usage:\n * nx run architecture:validate-architecture-unchanged\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport {\n writeTemplate,\n Option,\n RuleFailError,\n renderRuleFailForHuman,\n} from '@webpieces/rules-config';\nimport { generateReducedGraph } from '../../lib/graph-generator';\nimport { sortGraphTopologically } from '../../lib/graph-sorter';\nimport { compareGraphs } from '../../lib/graph-comparator';\nimport { loadBlessedGraph, graphFileExists } from '../../lib/graph-loader';\nimport type { DependenciesFile } from '../../lib/graph-loader';\nimport { collectProjectInfo, enrichGraph, MetadataValidationError } from '../../lib/graph-metadata';\nimport { TagTruthCheck } from '../../lib/tag-truth';\nimport { ApprovedWiringGraph } from '../../lib/runtime-wiring/approved-graph';\nimport type { ExternalSystemDecls } from '../../lib/api-usage/api-relations';\nimport { ApiContractFiles } from '../../lib/api-contract-files';\nimport type { ApiContractFileRefs } from '../../lib/api-contract-files';\nimport type { RemoteServices } from '../../lib/remote-services';\nimport { RuleGate } from '../../lib/rule-gate';\nimport type { EnhancedGraph } from '../../lib/graph-sorter';\nimport { toError } from '../../toError';\n\nexport interface ValidateArchitectureUnchangedOptions {\n graphPath?: string;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nconst TMP_MD_FILE = 'webpieces.dependencies.md';\n\n/**\n * Write the instructions documentation to .webpieces-logs/instruct-ai/.\n * Sourced from @webpieces/rules-config.\n */\nfunction writeTmpInstructionsFile(workspaceRoot: string): string {\n const mdPath = writeTemplate(workspaceRoot, TMP_MD_FILE);\n\n return mdPath;\n}\n\n/**\n * Report a current-vs-saved graph mismatch and write the AI instructions file.\n */\nfunction reportMismatch(summary: string, workspaceRoot: string): void {\n const mdPath = writeTmpInstructionsFile(workspaceRoot);\n\n console.error('❌ Architecture has changed since last update!');\n console.error('\\nDifferences:');\n console.error(summary);\n console.error('');\n console.error('⚠️ *** Refer to ' + mdPath + ' for instructions on how to fix *** ⚠️');\n console.error('');\n console.error('To fix:');\n console.error(' 1. Review the changes above');\n console.error(\n ' 2. If intentional, ASK USER to run: nx run architecture:generate since this is a critical change',\n );\n console.error(' 3. Commit the updated architecture/dependencies.json');\n}\n\n/**\n * Which APIs dependencies.json links to a contract file, compared by LINK only — an added or removed\n * API. The endpoints inside `architecture/apis/<Api>.json` are deliberately NOT compared (#949): an\n * endpoint change must not fail this rule. Null when the links match.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches reportMismatch in this file\nfunction describeContractLinkDrift(\n current: ApiContractFileRefs,\n saved: ApiContractFileRefs,\n): string | null {\n const names = [...new Set([...Object.keys(current), ...Object.keys(saved)])].sort();\n const changes: string[] = [];\n for (const name of names) {\n const a = current[name];\n const b = saved[name];\n if (a === undefined)\n changes.push(` - ${name}: linked in dependencies.json but no longer in source`);\n else if (b === undefined)\n changes.push(` + ${name}: in source but not linked from dependencies.json`);\n else if (a !== b) changes.push(` ~ ${name}: contract file link changed (${b} -> ${a})`);\n }\n if (changes.length === 0) return null;\n return `apiContractFiles drift (${changes.length} api(s)):\\n${changes.join('\\n')}`;\n}\n\n/**\n * Drift in EITHER side table of dependencies.json — the api contract-file links or the\n * external-system declarations — or null when both match. The first difference found is reported;\n * fixing it is the same single command either way, so listing both adds noise rather than information.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches describeContractLinkDrift above\nexport function describeTableDrift(\n current: CurrentArchitecture,\n saved: DependenciesFile,\n): string | null {\n const linkDrift = describeContractLinkDrift(current.apiContractFiles, saved.apiContractFiles);\n if (linkDrift !== null) return linkDrift;\n const systemDrift = describeExternalSystemDrift(current.externalSystems, saved.externalSystems);\n if (systemDrift !== null) return systemDrift;\n return describeRemoteServiceDrift(current.remoteServices, saved.remoteServices);\n}\n\n/**\n * The same drift report for the reviewed remote services (#1203), or null when they match. The table\n * is approval metadata, so a difference means the file changed under the generated graph.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches describeContractLinkDrift above\nfunction describeRemoteServiceDrift(current: RemoteServices, saved: RemoteServices): string | null {\n const names = [...new Set([...Object.keys(current), ...Object.keys(saved)])].sort();\n const changes: string[] = [];\n for (const name of names) {\n const a = current[name];\n const b = saved[name];\n if (a === undefined) changes.push(` - ${name}: in dependencies.json but no longer approved`);\n else if (b === undefined) changes.push(` + ${name}: approved but missing from dependencies.json`);\n else if (JSON.stringify(a) !== JSON.stringify(b))\n changes.push(` ~ ${name}: label/implements changed`);\n }\n if (changes.length === 0) return null;\n return `remoteServices drift (${changes.length} service(s)):\\n${changes.join('\\n')}`;\n}\n\n/**\n * The same drift report for the declared external systems, or null when they match. Named per\n * system so the message points at the database that changed rather than dumping two JSON blobs.\n */\n// webpieces-disable no-function-outside-class -- executor step helper, matches describeContractLinkDrift above\nfunction describeExternalSystemDrift(\n current: ExternalSystemDecls,\n saved: ExternalSystemDecls,\n): string | null {\n const names = [...new Set([...Object.keys(current), ...Object.keys(saved)])].sort();\n const changes: string[] = [];\n for (const name of names) {\n const a = current[name];\n const b = saved[name];\n if (a === undefined)\n changes.push(` - ${name}: in dependencies.json but no longer declared in source`);\n else if (b === undefined)\n changes.push(` + ${name}: declared in source but missing from dependencies.json`);\n else if (JSON.stringify(a) !== JSON.stringify(b))\n changes.push(` ~ ${name}: kind/label/declarers changed`);\n }\n if (changes.length === 0) return null;\n return `externalSystems drift (${changes.length} system(s)):\\n${changes.join('\\n')}`;\n}\n\n/**\n * Build the current dependency graph exactly as the generator does: reduce the nx\n * graph, sort into levels, enrich with metadata, and attach the derived\n * apiRelations — so this validator compares like-for-like against the committed file.\n */\nexport class CurrentGraphBuilder {\n async build(workspaceRoot: string, graphPath?: string): Promise<CurrentArchitecture> {\n console.log('📊 Generating current dependency graph...');\n const reducedGraph = await generateReducedGraph();\n console.log('🔄 Computing topological layers...');\n const currentGraph = sortGraphTopologically(reducedGraph);\n console.log('🏷️ Enriching graph with framework + responsibilities metadata...');\n const projectInfos = await collectProjectInfo();\n enrichGraph(currentGraph, projectInfos, workspaceRoot);\n new TagTruthCheck().assertTrue(currentGraph, projectInfos, workspaceRoot);\n new ApprovedWiringGraph().attach(workspaceRoot, currentGraph, projectInfos, graphPath);\n const saved = loadBlessedGraph(workspaceRoot, graphPath);\n if (saved === null)\n throw new RuleFailError(\n 'validate-runtime-architecture',\n 'Missing approved graph.',\n undefined,\n undefined,\n [\n new Option(\n 'Migrate src/wiring.ts and review runtime-deps.json and API contract approvals.',\n true,\n ),\n ],\n );\n return new CurrentArchitecture(\n currentGraph,\n saved.apiContractFiles,\n saved.externalSystems,\n saved.remoteServices,\n );\n }\n}\n\n/** The regenerated graph plus the tables beside it — everything dependencies.json holds. */\nexport class CurrentArchitecture {\n constructor(\n public readonly graph: EnhancedGraph,\n public readonly apiContractFiles: ApiContractFileRefs,\n public readonly externalSystems: ExternalSystemDecls,\n public readonly remoteServices: RemoteServices,\n ) {}\n}\n\n/** The bootstrap path: there is nothing to diff against yet, so say how to create it. */\n// webpieces-disable no-function-outside-class -- executor step helper, matches reportMismatch in this file\nfunction reportMissingGraph(): never {\n throw new RuleFailError(\n 'validate-runtime-architecture',\n 'Missing reviewed architecture/dependencies.json.',\n undefined,\n undefined,\n [\n new Option(\n 'Run owning API source build checks to emit contract candidates, review and copy them into architecture/apis/<ApiName>.json, and create dependencies.json with projects:{}, apiContractFiles:{\"<ApiName>\":\"apis/<ApiName>.json\"}, reviewed externalSystems, and (only when a uses targets a service outside this workspace) reviewed remoteServices. Approve tagged owners runtime-deps.json candidates, then run architecture:generate and review the resulting graph.',\n true,\n ),\n ],\n );\n}\n\nexport default async function runExecutor(\n options: ValidateArchitectureUnchangedOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n const graphPath = options.graphPath;\n const workspaceRoot = context.root;\n\n // Epoch-gateable: this rule diffs against the blessed architecture/dependencies.json, so\n // \"grandfather the current drift until <epoch>\" is meaningful — hence honorEpoch = true.\n if (new RuleGate().isDisabled(workspaceRoot, 'validate-architecture-unchanged', true)) {\n return { success: true };\n }\n\n console.log('\\n🔍 Validating Architecture Unchanged\\n');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Check if saved graph exists\n if (!graphFileExists(workspaceRoot, graphPath)) {\n reportMissingGraph();\n return { success: false };\n }\n\n // Steps 1-3: build + enrich + scan the current graph (same pipeline the\n // generator runs, so any drift is caught).\n const currentGraph = await new CurrentGraphBuilder().build(workspaceRoot, graphPath);\n\n // Step 4: Load saved graph\n console.log('📂 Loading saved graph...');\n const savedGraph = loadBlessedGraph(workspaceRoot, graphPath);\n\n if (!savedGraph) {\n console.error('❌ Could not load saved graph');\n return { success: false };\n }\n\n // Step 5: Compare graphs\n console.log('🔍 Comparing current graph to saved graph...');\n const comparison = compareGraphs(currentGraph.graph, savedGraph.projects);\n\n if (!comparison.identical) {\n reportMismatch(comparison.summary, workspaceRoot);\n return { success: false };\n }\n\n // Step 6: Compare the two side tables as well: which APIs are linked to a contract file, and\n // the external-system declarations. The endpoints inside architecture/apis/<Api>.json are\n // NOT compared — an endpoint change must never fail this rule (#949).\n const tableDrift = describeTableDrift(currentGraph, savedGraph);\n if (tableDrift !== null) {\n reportMismatch(tableDrift, workspaceRoot);\n return { success: false };\n }\n\n console.log('✅ Architecture unchanged - current graph matches saved graph');\n return { success: true };\n } catch (err: unknown) {\n const error = toError(err);\n // A RuleFailError (e.g. a dependencies.json still carrying the moved `apiContracts` key)\n // carries its cures in Option[]; render them rather than dropping them with `.message`.\n const rendered =\n error instanceof RuleFailError ? renderRuleFailForHuman(error) : error.message;\n console.error('❌ Architecture validation failed:', rendered);\n reportMetadataFailure(error, workspaceRoot);\n return { success: false };\n }\n}\n\n// webpieces-disable no-function-outside-class -- executor diagnostic formatting\nfunction reportMetadataFailure(error: Error, workspaceRoot: string): void {\n if (error instanceof MetadataValidationError) {\n const mdPath = writeTemplate(workspaceRoot, 'webpieces.responsibilities.md');\n console.error('');\n console.error(\n '⚠️ *** Refer to ' + mdPath + ' for how to author responsibilities.md files *** ⚠️',\n );\n }\n}\n"]}
package/src/index.d.ts CHANGED
@@ -28,7 +28,7 @@ export type { ApiDocMode } from './configs/api-doc-rules-config';
28
28
  export { ApiClientPackagesEntry, ApiLibDependenciesConfig, ApiLibPathConfig, FrameworkFolderEntry, FrameworkFolderConfig, ProductDependencyEntry, ProductTagsConfig } from './configs/tag-truth-configs';
29
29
  export { GraphRenderModel, RenderNode, RenderEdge, NodeTags } from './lib/graph-render-model';
30
30
  export { GraphMode, NodeModeDots, LegendFacts, ProductCount } from './lib/graph-color-modes';
31
- export { ProductMembership, RuntimeProductMembership, ProductPalette, ProductColor, ProductBoundary } from './lib/graph-products';
31
+ export { ProductMembership, RuntimeProductMembership, ProductPalette, ProductColor, ProductPaletteSlot, PRODUCT_PALETTE_SLOTS, ProductBoundary, } from './lib/graph-products';
32
32
  export { ProductDependencyMatrix } from './lib/product-dependencies';
33
33
  export { ProductResolver, ProductResolution, PRODUCT_TAG_PREFIX } from './lib/product-resolver';
34
34
  export { EntryPointLevels } from './lib/graph-entry-levels';
package/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EntryPointLevels = exports.PRODUCT_TAG_PREFIX = exports.ProductResolution = exports.ProductResolver = exports.ProductDependencyMatrix = exports.ProductBoundary = exports.ProductColor = exports.ProductPalette = exports.RuntimeProductMembership = exports.ProductMembership = exports.ProductCount = exports.LegendFacts = exports.NodeModeDots = exports.GraphMode = exports.NodeTags = exports.RenderEdge = exports.RenderNode = exports.GraphRenderModel = exports.ProductTagsConfig = exports.ProductDependencyEntry = exports.FrameworkFolderConfig = exports.FrameworkFolderEntry = exports.ApiLibPathConfig = exports.ApiLibDependenciesConfig = exports.ApiClientPackagesEntry = exports.ApiRulesForMcpConfig = exports.ApiRulesForOpenApiConfig = exports.API_DOC_MODES = exports.NoRootUnionApiTypeConfig = exports.WiringFormatConfig = exports.ValidateEslintSyncConfig = exports.ValidateVersionsLockedConfig = exports.ValidatePackageJsonConfig = exports.ValidateNoArchitectureCyclesConfig = exports.ValidateArchitectureUnchangedConfig = exports.MissingDesignAnnotationConfig = exports.DiGraphConfig = exports.NxWiringConfig = exports.RuntimeArchitectureConfig = exports.NoFileImportCyclesConfig = exports.STRUCTURAL_MODES = exports.createNodesV2 = void 0;
3
+ exports.EntryPointLevels = exports.PRODUCT_TAG_PREFIX = exports.ProductResolution = exports.ProductResolver = exports.ProductDependencyMatrix = exports.ProductBoundary = exports.PRODUCT_PALETTE_SLOTS = exports.ProductPaletteSlot = exports.ProductColor = exports.ProductPalette = exports.RuntimeProductMembership = exports.ProductMembership = exports.ProductCount = exports.LegendFacts = exports.NodeModeDots = exports.GraphMode = exports.NodeTags = exports.RenderEdge = exports.RenderNode = exports.GraphRenderModel = exports.ProductTagsConfig = exports.ProductDependencyEntry = exports.FrameworkFolderConfig = exports.FrameworkFolderEntry = exports.ApiLibPathConfig = exports.ApiLibDependenciesConfig = exports.ApiClientPackagesEntry = exports.ApiRulesForMcpConfig = exports.ApiRulesForOpenApiConfig = exports.API_DOC_MODES = exports.NoRootUnionApiTypeConfig = exports.WiringFormatConfig = exports.ValidateEslintSyncConfig = exports.ValidateVersionsLockedConfig = exports.ValidatePackageJsonConfig = exports.ValidateNoArchitectureCyclesConfig = exports.ValidateArchitectureUnchangedConfig = exports.MissingDesignAnnotationConfig = exports.DiGraphConfig = exports.NxWiringConfig = exports.RuntimeArchitectureConfig = exports.NoFileImportCyclesConfig = exports.STRUCTURAL_MODES = exports.createNodesV2 = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  tslib_1.__exportStar(require("./lib/graph-generator"), exports);
6
6
  tslib_1.__exportStar(require("./lib/graph-sorter"), exports);
@@ -62,6 +62,8 @@ Object.defineProperty(exports, "ProductMembership", { enumerable: true, get: fun
62
62
  Object.defineProperty(exports, "RuntimeProductMembership", { enumerable: true, get: function () { return graph_products_1.RuntimeProductMembership; } });
63
63
  Object.defineProperty(exports, "ProductPalette", { enumerable: true, get: function () { return graph_products_1.ProductPalette; } });
64
64
  Object.defineProperty(exports, "ProductColor", { enumerable: true, get: function () { return graph_products_1.ProductColor; } });
65
+ Object.defineProperty(exports, "ProductPaletteSlot", { enumerable: true, get: function () { return graph_products_1.ProductPaletteSlot; } });
66
+ Object.defineProperty(exports, "PRODUCT_PALETTE_SLOTS", { enumerable: true, get: function () { return graph_products_1.PRODUCT_PALETTE_SLOTS; } });
65
67
  Object.defineProperty(exports, "ProductBoundary", { enumerable: true, get: function () { return graph_products_1.ProductBoundary; } });
66
68
  var product_dependencies_1 = require("./lib/product-dependencies");
67
69
  Object.defineProperty(exports, "ProductDependencyMatrix", { enumerable: true, get: function () { return product_dependencies_1.ProductDependencyMatrix; } });
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/nx-webpieces-rules/src/index.ts"],"names":[],"mappings":";;;;AAAA,gEAAsC;AACtC,6DAAmC;AACnC,iEAAuC;AACvC,kEAAwC;AACxC,6DAAmC;AACnC,iEAAuC;AACvC,+DAAqC;AACrC,mEAAyC;AACzC,6EAAmD;AACnD,6DAAmC;AACnC,iEAAuC;AACvC,6DAAmC;AACnC,2EAAiD;AACjD,uEAA6C;AAC7C,qCAAyC;AAChC,8FADA,sBAAa,OACA;AACtB,kBAAe,EAAE,IAAI,EAAE,+BAA+B,EAAE,aAAa,EAAb,sBAAa,EAAE,CAAC;AAExE,uDAAyU;AAAhU,gHAAA,gBAAgB,OAAA;AAAE,wHAAA,wBAAwB,OAAA;AAAE,yHAAA,yBAAyB,OAAA;AAAE,8GAAA,cAAc,OAAA;AAAE,6GAAA,aAAa,OAAA;AAAE,6HAAA,6BAA6B,OAAA;AAAE,mIAAA,mCAAmC,OAAA;AAAE,kIAAA,kCAAkC,OAAA;AAAE,yHAAA,yBAAyB,OAAA;AAAE,4HAAA,4BAA4B,OAAA;AAAE,wHAAA,wBAAwB,OAAA;AAExS,uEAAoE;AAA3D,0HAAA,kBAAkB,OAAA;AAC3B,uEAA0E;AAAjE,gIAAA,wBAAwB,OAAA;AACjC,uEAA+G;AAAtG,qHAAA,aAAa,OAAA;AAAE,gIAAA,wBAAwB,OAAA;AAAE,4HAAA,oBAAoB,OAAA;AAEtE,iEAAyM;AAAhM,2HAAA,sBAAsB,OAAA;AAAE,6HAAA,wBAAwB,OAAA;AAAE,qHAAA,gBAAgB,OAAA;AAAE,yHAAA,oBAAoB,OAAA;AAAE,0HAAA,qBAAqB,OAAA;AAAE,2HAAA,sBAAsB,OAAA;AAAE,sHAAA,iBAAiB,OAAA;AAEnK,+DAA8F;AAArF,sHAAA,gBAAgB,OAAA;AAAE,gHAAA,UAAU,OAAA;AAAE,gHAAA,UAAU,OAAA;AAAE,8GAAA,QAAQ,OAAA;AAC3D,6DAA6F;AAApF,8GAAA,SAAS,OAAA;AAAE,iHAAA,YAAY,OAAA;AAAE,gHAAA,WAAW,OAAA;AAAE,iHAAA,YAAY,OAAA;AAC3D,uDAAkI;AAAzH,mHAAA,iBAAiB,OAAA;AAAE,0HAAA,wBAAwB,OAAA;AAAE,gHAAA,cAAc,OAAA;AAAE,8GAAA,YAAY,OAAA;AAAE,iHAAA,eAAe,OAAA;AACnG,mEAAqE;AAA5D,+HAAA,uBAAuB,OAAA;AAChC,2DAAgG;AAAvF,mHAAA,eAAe,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAAE,sHAAA,kBAAkB,OAAA;AAC/D,+DAA4D;AAAnD,sHAAA,gBAAgB,OAAA","sourcesContent":["export * from './lib/graph-generator';\nexport * from './lib/graph-sorter';\nexport * from './lib/graph-comparator';\nexport * from './lib/package-validator';\nexport * from './lib/graph-loader';\nexport * from './lib/graph-visualizer';\nexport * from './lib/graph-metadata';\nexport * from './lib/framework-resolver';\nexport * from './lib/runtime-participant-resolver';\nexport * from './lib/project-info';\nexport * from './lib/responsibilities';\nexport * from './lib/di-graph/dot';\nexport * from './lib/di-graph/design-visualizer';\nexport * from './lib/di-graph/design-finder';\nimport { createNodesV2 } from './plugin';\nexport { createNodesV2 };\nexport default { name: '@webpieces/nx-webpieces-rules', createNodesV2 };\n\nexport { STRUCTURAL_MODES, NoFileImportCyclesConfig, RuntimeArchitectureConfig, NxWiringConfig, DiGraphConfig, MissingDesignAnnotationConfig, ValidateArchitectureUnchangedConfig, ValidateNoArchitectureCyclesConfig, ValidatePackageJsonConfig, ValidateVersionsLockedConfig, ValidateEslintSyncConfig } from './configs/rule-configs';\nexport type { StructuralMode } from './configs/rule-configs';\nexport { WiringFormatConfig } from './configs/wiring-format-config';\nexport { NoRootUnionApiTypeConfig } from './configs/no-root-union-config';\nexport { API_DOC_MODES, ApiRulesForOpenApiConfig, ApiRulesForMcpConfig } from './configs/api-doc-rules-config';\nexport type { ApiDocMode } from './configs/api-doc-rules-config';\nexport { ApiClientPackagesEntry, ApiLibDependenciesConfig, ApiLibPathConfig, FrameworkFolderEntry, FrameworkFolderConfig, ProductDependencyEntry, ProductTagsConfig } from './configs/tag-truth-configs';\n\nexport { GraphRenderModel, RenderNode, RenderEdge, NodeTags } from './lib/graph-render-model';\nexport { GraphMode, NodeModeDots, LegendFacts, ProductCount } from './lib/graph-color-modes';\nexport { ProductMembership, RuntimeProductMembership, ProductPalette, ProductColor, ProductBoundary } from './lib/graph-products';\nexport { ProductDependencyMatrix } from './lib/product-dependencies';\nexport { ProductResolver, ProductResolution, PRODUCT_TAG_PREFIX } from './lib/product-resolver';\nexport { EntryPointLevels } from './lib/graph-entry-levels';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/nx-webpieces-rules/src/index.ts"],"names":[],"mappings":";;;;AAAA,gEAAsC;AACtC,6DAAmC;AACnC,iEAAuC;AACvC,kEAAwC;AACxC,6DAAmC;AACnC,iEAAuC;AACvC,+DAAqC;AACrC,mEAAyC;AACzC,6EAAmD;AACnD,6DAAmC;AACnC,iEAAuC;AACvC,6DAAmC;AACnC,2EAAiD;AACjD,uEAA6C;AAC7C,qCAAyC;AAChC,8FADA,sBAAa,OACA;AACtB,kBAAe,EAAE,IAAI,EAAE,+BAA+B,EAAE,aAAa,EAAb,sBAAa,EAAE,CAAC;AAExE,uDAAyU;AAAhU,gHAAA,gBAAgB,OAAA;AAAE,wHAAA,wBAAwB,OAAA;AAAE,yHAAA,yBAAyB,OAAA;AAAE,8GAAA,cAAc,OAAA;AAAE,6GAAA,aAAa,OAAA;AAAE,6HAAA,6BAA6B,OAAA;AAAE,mIAAA,mCAAmC,OAAA;AAAE,kIAAA,kCAAkC,OAAA;AAAE,yHAAA,yBAAyB,OAAA;AAAE,4HAAA,4BAA4B,OAAA;AAAE,wHAAA,wBAAwB,OAAA;AAExS,uEAAoE;AAA3D,0HAAA,kBAAkB,OAAA;AAC3B,uEAA0E;AAAjE,gIAAA,wBAAwB,OAAA;AACjC,uEAA+G;AAAtG,qHAAA,aAAa,OAAA;AAAE,gIAAA,wBAAwB,OAAA;AAAE,4HAAA,oBAAoB,OAAA;AAEtE,iEAAyM;AAAhM,2HAAA,sBAAsB,OAAA;AAAE,6HAAA,wBAAwB,OAAA;AAAE,qHAAA,gBAAgB,OAAA;AAAE,yHAAA,oBAAoB,OAAA;AAAE,0HAAA,qBAAqB,OAAA;AAAE,2HAAA,sBAAsB,OAAA;AAAE,sHAAA,iBAAiB,OAAA;AAEnK,+DAA8F;AAArF,sHAAA,gBAAgB,OAAA;AAAE,gHAAA,UAAU,OAAA;AAAE,gHAAA,UAAU,OAAA;AAAE,8GAAA,QAAQ,OAAA;AAC3D,6DAA6F;AAApF,8GAAA,SAAS,OAAA;AAAE,iHAAA,YAAY,OAAA;AAAE,gHAAA,WAAW,OAAA;AAAE,iHAAA,YAAY,OAAA;AAC3D,uDAQ8B;AAP1B,mHAAA,iBAAiB,OAAA;AACjB,0HAAA,wBAAwB,OAAA;AACxB,gHAAA,cAAc,OAAA;AACd,8GAAA,YAAY,OAAA;AACZ,oHAAA,kBAAkB,OAAA;AAClB,uHAAA,qBAAqB,OAAA;AACrB,iHAAA,eAAe,OAAA;AAEnB,mEAAqE;AAA5D,+HAAA,uBAAuB,OAAA;AAChC,2DAAgG;AAAvF,mHAAA,eAAe,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAAE,sHAAA,kBAAkB,OAAA;AAC/D,+DAA4D;AAAnD,sHAAA,gBAAgB,OAAA","sourcesContent":["export * from './lib/graph-generator';\nexport * from './lib/graph-sorter';\nexport * from './lib/graph-comparator';\nexport * from './lib/package-validator';\nexport * from './lib/graph-loader';\nexport * from './lib/graph-visualizer';\nexport * from './lib/graph-metadata';\nexport * from './lib/framework-resolver';\nexport * from './lib/runtime-participant-resolver';\nexport * from './lib/project-info';\nexport * from './lib/responsibilities';\nexport * from './lib/di-graph/dot';\nexport * from './lib/di-graph/design-visualizer';\nexport * from './lib/di-graph/design-finder';\nimport { createNodesV2 } from './plugin';\nexport { createNodesV2 };\nexport default { name: '@webpieces/nx-webpieces-rules', createNodesV2 };\n\nexport { STRUCTURAL_MODES, NoFileImportCyclesConfig, RuntimeArchitectureConfig, NxWiringConfig, DiGraphConfig, MissingDesignAnnotationConfig, ValidateArchitectureUnchangedConfig, ValidateNoArchitectureCyclesConfig, ValidatePackageJsonConfig, ValidateVersionsLockedConfig, ValidateEslintSyncConfig } from './configs/rule-configs';\nexport type { StructuralMode } from './configs/rule-configs';\nexport { WiringFormatConfig } from './configs/wiring-format-config';\nexport { NoRootUnionApiTypeConfig } from './configs/no-root-union-config';\nexport { API_DOC_MODES, ApiRulesForOpenApiConfig, ApiRulesForMcpConfig } from './configs/api-doc-rules-config';\nexport type { ApiDocMode } from './configs/api-doc-rules-config';\nexport { ApiClientPackagesEntry, ApiLibDependenciesConfig, ApiLibPathConfig, FrameworkFolderEntry, FrameworkFolderConfig, ProductDependencyEntry, ProductTagsConfig } from './configs/tag-truth-configs';\n\nexport { GraphRenderModel, RenderNode, RenderEdge, NodeTags } from './lib/graph-render-model';\nexport { GraphMode, NodeModeDots, LegendFacts, ProductCount } from './lib/graph-color-modes';\nexport {\n ProductMembership,\n RuntimeProductMembership,\n ProductPalette,\n ProductColor,\n ProductPaletteSlot,\n PRODUCT_PALETTE_SLOTS,\n ProductBoundary,\n} from './lib/graph-products';\nexport { ProductDependencyMatrix } from './lib/product-dependencies';\nexport { ProductResolver, ProductResolution, PRODUCT_TAG_PREFIX } from './lib/product-resolver';\nexport { EntryPointLevels } from './lib/graph-entry-levels';\n"]}
@@ -140,6 +140,13 @@ export declare class LegendFacts {
140
140
  noRuntime: boolean;
141
141
  /** One count per declared product, in palette (sorted-name) order; empty when none is declared. */
142
142
  products: ProductCount[];
143
+ /**
144
+ * The ONE palette every box was painted with (#1244), built over the full declared product set.
145
+ * The legend, the Filter's product chips and the crossing edges read their colors from it, never
146
+ * from a palette of their own: collision resolution depends on the set, so a second palette built
147
+ * from a subset could disagree with the boxes.
148
+ */
149
+ palette: ProductPalette;
143
150
  /** Boxes shared by every product (two or more declared). */
144
151
  sharedByAll: number;
145
152
  /** Boxes in no product. */
@@ -219,6 +219,13 @@ class LegendFacts {
219
219
  noRuntime = false;
220
220
  /** One count per declared product, in palette (sorted-name) order; empty when none is declared. */
221
221
  products = [];
222
+ /**
223
+ * The ONE palette every box was painted with (#1244), built over the full declared product set.
224
+ * The legend, the Filter's product chips and the crossing edges read their colors from it, never
225
+ * from a palette of their own: collision resolution depends on the set, so a second palette built
226
+ * from a subset could disagree with the boxes.
227
+ */
228
+ palette = new graph_products_1.ProductPalette([]);
222
229
  /** Boxes shared by every product (two or more declared). */
223
230
  sharedByAll = 0;
224
231
  /** Boxes in no product. */
@@ -290,6 +297,7 @@ class NodeModeStyler {
290
297
  }
291
298
  /** The Product section's counts: per product (total, and only-this-product), shared-by-all, none. */
292
299
  recordProducts(legend, facts, palette) {
300
+ legend.palette = palette;
293
301
  if (legend.products.length === 0 && palette.colors.length > 0) {
294
302
  legend.products = palette.names().map((product) => new ProductCount(product, 0, 0));
295
303
  }
@@ -1 +1 @@
1
- {"version":3,"file":"graph-color-modes.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-color-modes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Graph color modes (#1155, restyled by #1158)\n *\n * The architecture graph answers ONE question at a time instead of asking every box to encode two\n * (fill = framework AND border = role). Each box is emitted once per mode, so the page can switch\n * modes and re-render without regenerating anything. Every mode writes the SAME three lines on a box\n * (level + name, role, every framework tag); only the color changes:\n *\n * - RUNTIME \"where the code can run\". One runtime is a solid fill. One runtime plus a\n * specialization (angular/react inside browser, express inside node) is NESTED: an\n * outer frame in the base color around an inner rounded box in the specialization's\n * color, carrying the text. Several runtimes are full-height vertical stripes in the\n * fixed order browser | node | react-native, with the text written across them. The\n * dependency rule becomes visual: a box may depend on a box carrying every color it has.\n * - ARCHITECTURE \"servers · clients · APIs\". A solid fill by ROLE; framework color is not shown.\n * - IMPACT \"what changed\" — on this branch, or in the last commit (graph-impact.ts).\n * Projects owning a changed file are solid amber (\"touched\"); the rest of nx's affected set is light amber (\"affected\": their ci\n * re-runs); every transitive dependency of the affected set that is not itself\n * affected is light slate with a dashed border (\"build input\": compiled or restored\n * from cache, unchanged); everything else is grey. Which box is which is only known\n * per checkout, so every box carries all four variants and the page picks one from the\n * sidecar (graph-impact.ts). The state is never written on the box: color + legend.\n * The words are the Filter's: changed · dependent · dependency (built, unchanged) ·\n * not in this build.\n * - PRODUCT \"which products it belongs to\" (#1179, graph-products.ts). One product is a solid\n * fill in that product's palette color; two or more (but not all) are the same\n * vertical stripes the multi-runtime box uses, one per product; a box shared by EVERY\n * product is one neutral fill (otherwise a shared foundation would be four-stripe\n * noise); a box in no product is white with a dashed border. The Filter HIDES other\n * products' boxes; this mode keeps every box and makes ownership visible.\n */\n\nimport { KNOWN_FRAMEWORKS, KnownFramework } from '@webpieces/rules-sdk';\nimport { dotValue, htmlLabelText } from './dot-syntax';\nimport { PRODUCT_NONE_BORDER, PRODUCT_NONE_FILL, PRODUCT_SHARED_FILL, ProductColor, ProductPalette } from './graph-products';\nimport type { ProductDependencyEntry } from '../configs/tag-truth-configs';\n\nexport enum GraphMode {\n RUNTIME = 'runtime',\n ARCHITECTURE = 'architecture',\n IMPACT = 'impact',\n PRODUCT = 'product',\n}\n\n/** One selectable mode as the drawer's Color-by pulldown shows it. */\nexport class ModeInfo {\n constructor(\n public readonly mode: GraphMode,\n public readonly name: string,\n public readonly subtitle: string,\n ) {}\n}\n\n/** In key order: `1` selects the first, `2` the second, `3` the third, `4` the fourth. */\nexport const GRAPH_MODES: readonly ModeInfo[] = [\n new ModeInfo(GraphMode.RUNTIME, 'Runtime', 'where the code can run'),\n new ModeInfo(GraphMode.ARCHITECTURE, 'Architecture', 'servers · clients · APIs'),\n new ModeInfo(GraphMode.IMPACT, 'Impact', 'what changed'),\n new ModeInfo(GraphMode.PRODUCT, 'Product', 'which products it belongs to'),\n];\n\n/** Text on a light fill. */\nexport const DARK_TEXT = '#1a1c22';\n/** Text on a dark fill. */\nexport const LIGHT_TEXT = '#ffffff';\n\n/**\n * A framework value's color, the text color that reads on it, and the BASE runtime it is drawn\n * inside (itself, for a base).\n */\nexport class FrameworkStyle {\n constructor(\n public readonly framework: KnownFramework,\n public readonly base: KnownFramework,\n public readonly color: string,\n public readonly fontColor: string,\n public readonly description: string,\n ) {}\n\n isBase(): boolean {\n return this.framework === this.base;\n }\n}\n\n/**\n * Keyed by the shared vocabulary, so a framework added to KNOWN_FRAMEWORKS without a color here is a\n * COMPILE error — not a box silently painted grey and missing from the legend, which is exactly how\n * react-native shipped (#1155). Every base is mid-light, so dark text reads on every stripe.\n */\nexport const FRAMEWORK_STYLES: Record<KnownFramework, FrameworkStyle> = {\n browser: new FrameworkStyle('browser', 'browser', '#7d8cf2', DARK_TEXT, 'browser base runtime'),\n node: new FrameworkStyle('node', 'node', '#6fcf8a', DARK_TEXT, 'node base runtime'),\n 'react-native': new FrameworkStyle(\n 'react-native',\n 'react-native',\n '#34b8a6',\n DARK_TEXT,\n 'its own runtime, not a browser',\n ),\n angular: new FrameworkStyle('angular', 'browser', '#c8243f', LIGHT_TEXT, 'inside browser'),\n react: new FrameworkStyle('react', 'browser', '#7fd8ff', DARK_TEXT, 'inside browser'),\n express: new FrameworkStyle('express', 'node', '#2e7d4f', LIGHT_TEXT, 'inside node'),\n};\n\n/** Stripe order, left to right. Fixed, so the same set always reads the same way. */\nexport const BASE_ORDER: readonly KnownFramework[] = ['browser', 'node', 'react-native'];\n\n/**\n * The Filter popover's Runtime chips, and the order line 3 of a box lists framework tags in: the\n * bases first, then the specializations.\n */\nexport const FRAMEWORK_ORDER: readonly KnownFramework[] = [\n 'browser',\n 'node',\n 'react-native',\n 'angular',\n 'react',\n 'express',\n];\n\n/** A box with no known framework tag. */\nexport const NO_RUNTIME_COLOR = '#e4e6ec';\n\n/** The class Graphviz stamps on a multi-runtime box's `<g>`: its outline is its LAST shape. */\nexport const STRIPED_CLASS = 'wp-striped';\n\n/** Margin of base color around a specialization's inner box. */\nconst NEST_PAD = 5;\n/** Padding between the inner box's edge and its text. */\nconst INNER_PAD = 6;\n\n/** A role's solid fill and the text color that stays readable on it. */\nexport class RoleStyle {\n constructor(\n public readonly role: string,\n public readonly fill: string,\n public readonly fontColor: string,\n public readonly description: string,\n ) {}\n}\n\n/**\n * Every role role-resolver knows, in legend order (runnable things first) — also the Filter popover's\n * Role chips. `bundle` is indigo so no box color equals the page's violet accent.\n */\nexport const ROLE_STYLES: readonly RoleStyle[] = [\n new RoleStyle('server', '#4caf50', LIGHT_TEXT, 'runnable server'),\n new RoleStyle('client', '#e5533d', LIGHT_TEXT, 'browser or mobile client app'),\n new RoleStyle('app', '#1e88e5', LIGHT_TEXT, 'runnable non-HTTP app'),\n new RoleStyle('bundle', '#4b44c8', LIGHT_TEXT, 'bundles several apps'),\n new RoleStyle('api-lib', '#f08a24', DARK_TEXT, 'contract + DTOs'),\n new RoleStyle('api-client', '#1a9aa6', LIGHT_TEXT, 'contract + SDK implementation'),\n new RoleStyle('designed-lib', '#7d8597', LIGHT_TEXT, 'library with a generated design'),\n new RoleStyle('lib', '#d7dae2', DARK_TEXT, 'plain library'),\n];\n\n/** The four impact shades (graph-impact.ts decides which box gets which). */\nexport const IMPACT_TOUCHED = '#f5a524';\nexport const IMPACT_AFFECTED = '#fde3b0';\nexport const IMPACT_BUILD_INPUT = '#e3e9f2';\nexport const IMPACT_BUILD_INPUT_BORDER = '#7c8aa3';\nexport const IMPACT_UNTOUCHED = '#eef0f4';\nconst IMPACT_UNTOUCHED_TEXT = '#6b7180';\n\n/** What a box's per-mode rendering — and the page's Filter — is computed from. */\nexport class NodeFacts {\n constructor(\n public readonly nodeId: string,\n public readonly shortName: string,\n public readonly level: number,\n public readonly role: string,\n public readonly frameworks: string[],\n /** The products the project belongs to (dependencies.json `products`), sorted; empty for none. */\n public readonly products: string[],\n public readonly summary: string = '',\n ) {}\n}\n\n/** One box's DOT statement for every mode (and for each impact state). */\nexport class NodeModeDots {\n constructor(\n public readonly runtime: string,\n public readonly architecture: string,\n public readonly touched: string,\n public readonly affected: string,\n public readonly buildInput: string,\n public readonly untouched: string,\n public readonly product: string,\n ) {}\n}\n\n/** How many drawn boxes one product holds, and how many of them no other product does. */\nexport class ProductCount {\n constructor(\n public readonly product: string,\n public total: number,\n public only: number,\n ) {}\n}\n\n/** Which colors and roles the drawn projects actually use, so the legend lists exactly those. */\nexport class LegendFacts {\n frameworks: string[] = [];\n roles: string[] = [];\n multiRuntime = false;\n noRuntime = false;\n /** One count per declared product, in palette (sorted-name) order; empty when none is declared. */\n products: ProductCount[] = [];\n /** Boxes shared by every product (two or more declared). */\n sharedByAll = 0;\n /** Boxes in no product. */\n noProduct = 0;\n /** Some box belongs to two or more products, but not to every one: it is striped. */\n multiProduct = false;\n /** Dependency edges crossing into another product (#1204), drawn dashed in the Product mode. */\n crossProductEdges = 0;\n /**\n * The `product-tags` rule's matrix (#1204), listed in the Product legend; null when the rule is\n * OFF or the page was drawn without it.\n */\n productDependencies: ProductDependencyEntry[] | null = null;\n}\n\nexport class NodeModeStyler {\n styleOf(framework: string): FrameworkStyle | undefined {\n if (!(KNOWN_FRAMEWORKS as readonly string[]).includes(framework)) return undefined;\n return FRAMEWORK_STYLES[framework as KnownFramework];\n }\n\n roleStyle(role: string): RoleStyle {\n const style = ROLE_STYLES.find((candidate: RoleStyle): boolean => candidate.role === role);\n return style ?? (ROLE_STYLES.find((s: RoleStyle): boolean => s.role === 'lib') as RoleStyle);\n }\n\n /** Every role the renderer styles; a spec asserts this covers role-resolver's KNOWN_ROLES. */\n styledRoles(): string[] {\n return ROLE_STYLES.map((style: RoleStyle): string => style.role);\n }\n\n /** The base runtimes of a framework set, in stripe order (a specialization implies its base). */\n bases(frameworks: string[]): KnownFramework[] {\n const present = new Set<KnownFramework>();\n for (const framework of frameworks) {\n const style = this.styleOf(framework);\n if (style !== undefined) present.add(style.base);\n }\n return BASE_ORDER.filter((base: KnownFramework): boolean => present.has(base));\n }\n\n /** The specialization drawn inside `base`, if the set carries one. */\n specialization(base: KnownFramework, frameworks: string[]): FrameworkStyle | undefined {\n for (const framework of KNOWN_FRAMEWORKS) {\n const style = FRAMEWORK_STYLES[framework];\n if (style.isBase() || style.base !== base) continue;\n if (frameworks.includes(framework)) return style;\n }\n return undefined;\n }\n\n dots(facts: NodeFacts, palette: ProductPalette): NodeModeDots {\n return new NodeModeDots(\n this.runtime(facts),\n this.plain(facts, this.roleStyle(facts.role).fill, this.roleStyle(facts.role).fontColor, ''),\n this.plain(facts, IMPACT_TOUCHED, DARK_TEXT, ''),\n this.plain(facts, IMPACT_AFFECTED, DARK_TEXT, `, color=\"${IMPACT_TOUCHED}\", penwidth=2`),\n this.plain(\n facts,\n IMPACT_BUILD_INPUT,\n DARK_TEXT,\n `, color=\"${IMPACT_BUILD_INPUT_BORDER}\", penwidth=1.5`,\n 'filled,dashed',\n ),\n this.plain(facts, IMPACT_UNTOUCHED, IMPACT_UNTOUCHED_TEXT, ', color=\"#b4b9c4\"'),\n this.product(facts, palette),\n );\n }\n\n /** Fold one drawn box into the legend facts. */\n record(legend: LegendFacts, facts: NodeFacts, palette: ProductPalette): void {\n this.recordProducts(legend, facts, palette);\n for (const framework of facts.frameworks) {\n if (this.styleOf(framework) !== undefined && !legend.frameworks.includes(framework))\n legend.frameworks.push(framework);\n }\n const role = this.roleStyle(facts.role).role;\n if (!legend.roles.includes(role)) legend.roles.push(role);\n const bases = this.bases(facts.frameworks);\n if (bases.length > 1) legend.multiRuntime = true;\n if (bases.length === 0) legend.noRuntime = true;\n }\n\n /** The Product section's counts: per product (total, and only-this-product), shared-by-all, none. */\n private recordProducts(legend: LegendFacts, facts: NodeFacts, palette: ProductPalette): void {\n if (legend.products.length === 0 && palette.colors.length > 0) {\n legend.products = palette.names().map((product: string): ProductCount => new ProductCount(product, 0, 0));\n }\n if (facts.products.length === 0) legend.noProduct++;\n if (palette.sharedByAll(facts.products)) legend.sharedByAll++;\n else if (facts.products.length > 1) legend.multiProduct = true;\n for (const count of legend.products) {\n if (!facts.products.includes(count.product)) continue;\n count.total++;\n if (facts.products.length === 1) count.only++;\n }\n }\n\n /**\n * Line 3 of every box: every framework tag, bases before specializations, any tag outside the\n * shared vocabulary last (it still runs somewhere somebody declared).\n */\n frameworkLine(frameworks: string[]): string {\n if (frameworks.length === 0) return 'no framework tag';\n const known = FRAMEWORK_ORDER.filter((framework: KnownFramework): boolean =>\n frameworks.includes(framework),\n );\n const unknown = frameworks.filter((framework: string): boolean => this.styleOf(framework) === undefined);\n return [...known, ...unknown].join(' · ');\n }\n\n /**\n * The three lines, identical in every mode: `L3 name` (level dimmed, name bold), the role, and\n * the framework tags. The level is dimmed by giving its text color an alpha channel, which\n * Graphviz writes as `fill-opacity`, so it dims on any fill.\n */\n labelText(facts: NodeFacts, fontColor: string): string {\n return (\n `<FONT COLOR=\"${fontColor}99\">L${facts.level}</FONT>&#160;&#160;<B>${htmlLabelText(facts.shortName)}</B>` +\n `<BR/>${htmlLabelText(facts.role)}<BR/>${htmlLabelText(this.frameworkLine(facts.frameworks))}` +\n (facts.summary === '' ? '' : `<BR/>${htmlLabelText(facts.summary)}`)\n );\n }\n\n /** `filled` for one runtime; equal `striped` weights for several (the last takes the remainder). */\n stripeAttrs(bases: KnownFramework[]): string {\n return this.stripes(bases.map((base: KnownFramework): string => FRAMEWORK_STYLES[base].color));\n }\n\n /**\n * One equal vertical stripe per color — the renderer the multi-runtime box and the multi-product\n * box share. A single color is a plain fill.\n */\n stripes(colors: string[]): string {\n if (colors.length === 1) return `style=\"filled\", fillcolor=\"${colors[0]}\"`;\n const share = (1 / colors.length).toFixed(3);\n const weighted = colors.map((color: string, index: number): string =>\n index === colors.length - 1 ? color : `${color};${share}`,\n );\n return `style=\"striped\", fillcolor=\"${weighted.join(':')}\", class=\"${STRIPED_CLASS}\"`;\n }\n\n private statement(facts: NodeFacts, attrs: string, label: string): string {\n return ` \"${dotValue(facts.nodeId)}\" [${attrs}, label=<${label}>];\\n`;\n }\n\n /** A solid fill, the three lines on it. `extra` carries border attributes. */\n private plain(facts: NodeFacts, fill: string, fontColor: string, extra: string, style = 'filled'): string {\n return this.statement(\n facts,\n `style=\"${style}\", fillcolor=\"${fill}\", fontcolor=\"${fontColor}\"${extra}`,\n this.labelText(facts, fontColor),\n );\n }\n\n /**\n * Product mode (#1179): one product solid in its color; several (not all) striped, one stripe per\n * product; every product the neutral shared fill; no product a white box with a dashed border.\n */\n private product(facts: NodeFacts, palette: ProductPalette): string {\n if (facts.products.length === 0)\n return this.plain(facts, PRODUCT_NONE_FILL, DARK_TEXT, `, color=\"${PRODUCT_NONE_BORDER}\", penwidth=1.5`, 'filled,dashed');\n if (palette.sharedByAll(facts.products)) return this.plain(facts, PRODUCT_SHARED_FILL, DARK_TEXT, '');\n const colors = facts.products.map((product: string): ProductColor => palette.colorOf(product));\n if (colors.length === 1) return this.plain(facts, colors[0].color, colors[0].fontColor, '');\n return this.statement(\n facts,\n `${this.stripes(colors.map((color: ProductColor): string => color.color))}, fontcolor=\"${DARK_TEXT}\"`,\n this.labelText(facts, DARK_TEXT),\n );\n }\n\n /**\n * Runtime mode. No runtime, or one runtime with no specialization: a solid fill. One runtime with a\n * specialization: NESTED. Several runtimes: full-height stripes with the text across them (a\n * specialization on such a box shows in line 3 only).\n */\n private runtime(facts: NodeFacts): string {\n const bases = this.bases(facts.frameworks);\n if (bases.length === 0) return this.plain(facts, NO_RUNTIME_COLOR, DARK_TEXT, '');\n if (bases.length > 1)\n return this.statement(\n facts,\n `${this.stripeAttrs(bases)}, fontcolor=\"${DARK_TEXT}\"`,\n this.labelText(facts, DARK_TEXT),\n );\n const base = FRAMEWORK_STYLES[bases[0]];\n const inner = this.specialization(bases[0], facts.frameworks);\n if (inner === undefined) return this.plain(facts, base.color, base.fontColor, '');\n return this.statement(\n facts,\n `style=\"filled\", fillcolor=\"${base.color}\", fontcolor=\"${inner.fontColor}\", margin=0`,\n this.nestedTable(base.color, inner, this.labelText(facts, inner.fontColor)),\n );\n }\n\n /**\n * An outer cell in the base color whose padding is the visible frame, holding an inner ROUNDED\n * table in the specialization's color that carries the text. The node's own polygon stays its\n * FIRST shape, so the hover glow and the lock outline land on the outer box only.\n */\n private nestedTable(base: string, inner: FrameworkStyle, text: string): string {\n return (\n '<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">' +\n `<TR><TD BGCOLOR=\"${base}\" CELLPADDING=\"${NEST_PAD}\">` +\n `<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"${INNER_PAD}\" BGCOLOR=\"${inner.color}\" STYLE=\"rounded\">` +\n `<TR><TD>${text}</TD></TR></TABLE></TD></TR></TABLE>`\n );\n }\n}\n"]}
1
+ {"version":3,"file":"graph-color-modes.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-color-modes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Graph color modes (#1155, restyled by #1158)\n *\n * The architecture graph answers ONE question at a time instead of asking every box to encode two\n * (fill = framework AND border = role). Each box is emitted once per mode, so the page can switch\n * modes and re-render without regenerating anything. Every mode writes the SAME three lines on a box\n * (level + name, role, every framework tag); only the color changes:\n *\n * - RUNTIME \"where the code can run\". One runtime is a solid fill. One runtime plus a\n * specialization (angular/react inside browser, express inside node) is NESTED: an\n * outer frame in the base color around an inner rounded box in the specialization's\n * color, carrying the text. Several runtimes are full-height vertical stripes in the\n * fixed order browser | node | react-native, with the text written across them. The\n * dependency rule becomes visual: a box may depend on a box carrying every color it has.\n * - ARCHITECTURE \"servers · clients · APIs\". A solid fill by ROLE; framework color is not shown.\n * - IMPACT \"what changed\" — on this branch, or in the last commit (graph-impact.ts).\n * Projects owning a changed file are solid amber (\"touched\"); the rest of nx's affected set is light amber (\"affected\": their ci\n * re-runs); every transitive dependency of the affected set that is not itself\n * affected is light slate with a dashed border (\"build input\": compiled or restored\n * from cache, unchanged); everything else is grey. Which box is which is only known\n * per checkout, so every box carries all four variants and the page picks one from the\n * sidecar (graph-impact.ts). The state is never written on the box: color + legend.\n * The words are the Filter's: changed · dependent · dependency (built, unchanged) ·\n * not in this build.\n * - PRODUCT \"which products it belongs to\" (#1179, graph-products.ts). One product is a solid\n * fill in that product's palette color; two or more (but not all) are the same\n * vertical stripes the multi-runtime box uses, one per product; a box shared by EVERY\n * product is one neutral fill (otherwise a shared foundation would be four-stripe\n * noise); a box in no product is white with a dashed border. The Filter HIDES other\n * products' boxes; this mode keeps every box and makes ownership visible.\n */\n\nimport { KNOWN_FRAMEWORKS, KnownFramework } from '@webpieces/rules-sdk';\nimport { dotValue, htmlLabelText } from './dot-syntax';\nimport { PRODUCT_NONE_BORDER, PRODUCT_NONE_FILL, PRODUCT_SHARED_FILL, ProductColor, ProductPalette } from './graph-products';\nimport type { ProductDependencyEntry } from '../configs/tag-truth-configs';\n\nexport enum GraphMode {\n RUNTIME = 'runtime',\n ARCHITECTURE = 'architecture',\n IMPACT = 'impact',\n PRODUCT = 'product',\n}\n\n/** One selectable mode as the drawer's Color-by pulldown shows it. */\nexport class ModeInfo {\n constructor(\n public readonly mode: GraphMode,\n public readonly name: string,\n public readonly subtitle: string,\n ) {}\n}\n\n/** In key order: `1` selects the first, `2` the second, `3` the third, `4` the fourth. */\nexport const GRAPH_MODES: readonly ModeInfo[] = [\n new ModeInfo(GraphMode.RUNTIME, 'Runtime', 'where the code can run'),\n new ModeInfo(GraphMode.ARCHITECTURE, 'Architecture', 'servers · clients · APIs'),\n new ModeInfo(GraphMode.IMPACT, 'Impact', 'what changed'),\n new ModeInfo(GraphMode.PRODUCT, 'Product', 'which products it belongs to'),\n];\n\n/** Text on a light fill. */\nexport const DARK_TEXT = '#1a1c22';\n/** Text on a dark fill. */\nexport const LIGHT_TEXT = '#ffffff';\n\n/**\n * A framework value's color, the text color that reads on it, and the BASE runtime it is drawn\n * inside (itself, for a base).\n */\nexport class FrameworkStyle {\n constructor(\n public readonly framework: KnownFramework,\n public readonly base: KnownFramework,\n public readonly color: string,\n public readonly fontColor: string,\n public readonly description: string,\n ) {}\n\n isBase(): boolean {\n return this.framework === this.base;\n }\n}\n\n/**\n * Keyed by the shared vocabulary, so a framework added to KNOWN_FRAMEWORKS without a color here is a\n * COMPILE error — not a box silently painted grey and missing from the legend, which is exactly how\n * react-native shipped (#1155). Every base is mid-light, so dark text reads on every stripe.\n */\nexport const FRAMEWORK_STYLES: Record<KnownFramework, FrameworkStyle> = {\n browser: new FrameworkStyle('browser', 'browser', '#7d8cf2', DARK_TEXT, 'browser base runtime'),\n node: new FrameworkStyle('node', 'node', '#6fcf8a', DARK_TEXT, 'node base runtime'),\n 'react-native': new FrameworkStyle(\n 'react-native',\n 'react-native',\n '#34b8a6',\n DARK_TEXT,\n 'its own runtime, not a browser',\n ),\n angular: new FrameworkStyle('angular', 'browser', '#c8243f', LIGHT_TEXT, 'inside browser'),\n react: new FrameworkStyle('react', 'browser', '#7fd8ff', DARK_TEXT, 'inside browser'),\n express: new FrameworkStyle('express', 'node', '#2e7d4f', LIGHT_TEXT, 'inside node'),\n};\n\n/** Stripe order, left to right. Fixed, so the same set always reads the same way. */\nexport const BASE_ORDER: readonly KnownFramework[] = ['browser', 'node', 'react-native'];\n\n/**\n * The Filter popover's Runtime chips, and the order line 3 of a box lists framework tags in: the\n * bases first, then the specializations.\n */\nexport const FRAMEWORK_ORDER: readonly KnownFramework[] = [\n 'browser',\n 'node',\n 'react-native',\n 'angular',\n 'react',\n 'express',\n];\n\n/** A box with no known framework tag. */\nexport const NO_RUNTIME_COLOR = '#e4e6ec';\n\n/** The class Graphviz stamps on a multi-runtime box's `<g>`: its outline is its LAST shape. */\nexport const STRIPED_CLASS = 'wp-striped';\n\n/** Margin of base color around a specialization's inner box. */\nconst NEST_PAD = 5;\n/** Padding between the inner box's edge and its text. */\nconst INNER_PAD = 6;\n\n/** A role's solid fill and the text color that stays readable on it. */\nexport class RoleStyle {\n constructor(\n public readonly role: string,\n public readonly fill: string,\n public readonly fontColor: string,\n public readonly description: string,\n ) {}\n}\n\n/**\n * Every role role-resolver knows, in legend order (runnable things first) — also the Filter popover's\n * Role chips. `bundle` is indigo so no box color equals the page's violet accent.\n */\nexport const ROLE_STYLES: readonly RoleStyle[] = [\n new RoleStyle('server', '#4caf50', LIGHT_TEXT, 'runnable server'),\n new RoleStyle('client', '#e5533d', LIGHT_TEXT, 'browser or mobile client app'),\n new RoleStyle('app', '#1e88e5', LIGHT_TEXT, 'runnable non-HTTP app'),\n new RoleStyle('bundle', '#4b44c8', LIGHT_TEXT, 'bundles several apps'),\n new RoleStyle('api-lib', '#f08a24', DARK_TEXT, 'contract + DTOs'),\n new RoleStyle('api-client', '#1a9aa6', LIGHT_TEXT, 'contract + SDK implementation'),\n new RoleStyle('designed-lib', '#7d8597', LIGHT_TEXT, 'library with a generated design'),\n new RoleStyle('lib', '#d7dae2', DARK_TEXT, 'plain library'),\n];\n\n/** The four impact shades (graph-impact.ts decides which box gets which). */\nexport const IMPACT_TOUCHED = '#f5a524';\nexport const IMPACT_AFFECTED = '#fde3b0';\nexport const IMPACT_BUILD_INPUT = '#e3e9f2';\nexport const IMPACT_BUILD_INPUT_BORDER = '#7c8aa3';\nexport const IMPACT_UNTOUCHED = '#eef0f4';\nconst IMPACT_UNTOUCHED_TEXT = '#6b7180';\n\n/** What a box's per-mode rendering — and the page's Filter — is computed from. */\nexport class NodeFacts {\n constructor(\n public readonly nodeId: string,\n public readonly shortName: string,\n public readonly level: number,\n public readonly role: string,\n public readonly frameworks: string[],\n /** The products the project belongs to (dependencies.json `products`), sorted; empty for none. */\n public readonly products: string[],\n public readonly summary: string = '',\n ) {}\n}\n\n/** One box's DOT statement for every mode (and for each impact state). */\nexport class NodeModeDots {\n constructor(\n public readonly runtime: string,\n public readonly architecture: string,\n public readonly touched: string,\n public readonly affected: string,\n public readonly buildInput: string,\n public readonly untouched: string,\n public readonly product: string,\n ) {}\n}\n\n/** How many drawn boxes one product holds, and how many of them no other product does. */\nexport class ProductCount {\n constructor(\n public readonly product: string,\n public total: number,\n public only: number,\n ) {}\n}\n\n/** Which colors and roles the drawn projects actually use, so the legend lists exactly those. */\nexport class LegendFacts {\n frameworks: string[] = [];\n roles: string[] = [];\n multiRuntime = false;\n noRuntime = false;\n /** One count per declared product, in palette (sorted-name) order; empty when none is declared. */\n products: ProductCount[] = [];\n /**\n * The ONE palette every box was painted with (#1244), built over the full declared product set.\n * The legend, the Filter's product chips and the crossing edges read their colors from it, never\n * from a palette of their own: collision resolution depends on the set, so a second palette built\n * from a subset could disagree with the boxes.\n */\n palette: ProductPalette = new ProductPalette([]);\n /** Boxes shared by every product (two or more declared). */\n sharedByAll = 0;\n /** Boxes in no product. */\n noProduct = 0;\n /** Some box belongs to two or more products, but not to every one: it is striped. */\n multiProduct = false;\n /** Dependency edges crossing into another product (#1204), drawn dashed in the Product mode. */\n crossProductEdges = 0;\n /**\n * The `product-tags` rule's matrix (#1204), listed in the Product legend; null when the rule is\n * OFF or the page was drawn without it.\n */\n productDependencies: ProductDependencyEntry[] | null = null;\n}\n\nexport class NodeModeStyler {\n styleOf(framework: string): FrameworkStyle | undefined {\n if (!(KNOWN_FRAMEWORKS as readonly string[]).includes(framework)) return undefined;\n return FRAMEWORK_STYLES[framework as KnownFramework];\n }\n\n roleStyle(role: string): RoleStyle {\n const style = ROLE_STYLES.find((candidate: RoleStyle): boolean => candidate.role === role);\n return style ?? (ROLE_STYLES.find((s: RoleStyle): boolean => s.role === 'lib') as RoleStyle);\n }\n\n /** Every role the renderer styles; a spec asserts this covers role-resolver's KNOWN_ROLES. */\n styledRoles(): string[] {\n return ROLE_STYLES.map((style: RoleStyle): string => style.role);\n }\n\n /** The base runtimes of a framework set, in stripe order (a specialization implies its base). */\n bases(frameworks: string[]): KnownFramework[] {\n const present = new Set<KnownFramework>();\n for (const framework of frameworks) {\n const style = this.styleOf(framework);\n if (style !== undefined) present.add(style.base);\n }\n return BASE_ORDER.filter((base: KnownFramework): boolean => present.has(base));\n }\n\n /** The specialization drawn inside `base`, if the set carries one. */\n specialization(base: KnownFramework, frameworks: string[]): FrameworkStyle | undefined {\n for (const framework of KNOWN_FRAMEWORKS) {\n const style = FRAMEWORK_STYLES[framework];\n if (style.isBase() || style.base !== base) continue;\n if (frameworks.includes(framework)) return style;\n }\n return undefined;\n }\n\n dots(facts: NodeFacts, palette: ProductPalette): NodeModeDots {\n return new NodeModeDots(\n this.runtime(facts),\n this.plain(facts, this.roleStyle(facts.role).fill, this.roleStyle(facts.role).fontColor, ''),\n this.plain(facts, IMPACT_TOUCHED, DARK_TEXT, ''),\n this.plain(facts, IMPACT_AFFECTED, DARK_TEXT, `, color=\"${IMPACT_TOUCHED}\", penwidth=2`),\n this.plain(\n facts,\n IMPACT_BUILD_INPUT,\n DARK_TEXT,\n `, color=\"${IMPACT_BUILD_INPUT_BORDER}\", penwidth=1.5`,\n 'filled,dashed',\n ),\n this.plain(facts, IMPACT_UNTOUCHED, IMPACT_UNTOUCHED_TEXT, ', color=\"#b4b9c4\"'),\n this.product(facts, palette),\n );\n }\n\n /** Fold one drawn box into the legend facts. */\n record(legend: LegendFacts, facts: NodeFacts, palette: ProductPalette): void {\n this.recordProducts(legend, facts, palette);\n for (const framework of facts.frameworks) {\n if (this.styleOf(framework) !== undefined && !legend.frameworks.includes(framework))\n legend.frameworks.push(framework);\n }\n const role = this.roleStyle(facts.role).role;\n if (!legend.roles.includes(role)) legend.roles.push(role);\n const bases = this.bases(facts.frameworks);\n if (bases.length > 1) legend.multiRuntime = true;\n if (bases.length === 0) legend.noRuntime = true;\n }\n\n /** The Product section's counts: per product (total, and only-this-product), shared-by-all, none. */\n private recordProducts(legend: LegendFacts, facts: NodeFacts, palette: ProductPalette): void {\n legend.palette = palette;\n if (legend.products.length === 0 && palette.colors.length > 0) {\n legend.products = palette.names().map((product: string): ProductCount => new ProductCount(product, 0, 0));\n }\n if (facts.products.length === 0) legend.noProduct++;\n if (palette.sharedByAll(facts.products)) legend.sharedByAll++;\n else if (facts.products.length > 1) legend.multiProduct = true;\n for (const count of legend.products) {\n if (!facts.products.includes(count.product)) continue;\n count.total++;\n if (facts.products.length === 1) count.only++;\n }\n }\n\n /**\n * Line 3 of every box: every framework tag, bases before specializations, any tag outside the\n * shared vocabulary last (it still runs somewhere somebody declared).\n */\n frameworkLine(frameworks: string[]): string {\n if (frameworks.length === 0) return 'no framework tag';\n const known = FRAMEWORK_ORDER.filter((framework: KnownFramework): boolean =>\n frameworks.includes(framework),\n );\n const unknown = frameworks.filter((framework: string): boolean => this.styleOf(framework) === undefined);\n return [...known, ...unknown].join(' · ');\n }\n\n /**\n * The three lines, identical in every mode: `L3 name` (level dimmed, name bold), the role, and\n * the framework tags. The level is dimmed by giving its text color an alpha channel, which\n * Graphviz writes as `fill-opacity`, so it dims on any fill.\n */\n labelText(facts: NodeFacts, fontColor: string): string {\n return (\n `<FONT COLOR=\"${fontColor}99\">L${facts.level}</FONT>&#160;&#160;<B>${htmlLabelText(facts.shortName)}</B>` +\n `<BR/>${htmlLabelText(facts.role)}<BR/>${htmlLabelText(this.frameworkLine(facts.frameworks))}` +\n (facts.summary === '' ? '' : `<BR/>${htmlLabelText(facts.summary)}`)\n );\n }\n\n /** `filled` for one runtime; equal `striped` weights for several (the last takes the remainder). */\n stripeAttrs(bases: KnownFramework[]): string {\n return this.stripes(bases.map((base: KnownFramework): string => FRAMEWORK_STYLES[base].color));\n }\n\n /**\n * One equal vertical stripe per color — the renderer the multi-runtime box and the multi-product\n * box share. A single color is a plain fill.\n */\n stripes(colors: string[]): string {\n if (colors.length === 1) return `style=\"filled\", fillcolor=\"${colors[0]}\"`;\n const share = (1 / colors.length).toFixed(3);\n const weighted = colors.map((color: string, index: number): string =>\n index === colors.length - 1 ? color : `${color};${share}`,\n );\n return `style=\"striped\", fillcolor=\"${weighted.join(':')}\", class=\"${STRIPED_CLASS}\"`;\n }\n\n private statement(facts: NodeFacts, attrs: string, label: string): string {\n return ` \"${dotValue(facts.nodeId)}\" [${attrs}, label=<${label}>];\\n`;\n }\n\n /** A solid fill, the three lines on it. `extra` carries border attributes. */\n private plain(facts: NodeFacts, fill: string, fontColor: string, extra: string, style = 'filled'): string {\n return this.statement(\n facts,\n `style=\"${style}\", fillcolor=\"${fill}\", fontcolor=\"${fontColor}\"${extra}`,\n this.labelText(facts, fontColor),\n );\n }\n\n /**\n * Product mode (#1179): one product solid in its color; several (not all) striped, one stripe per\n * product; every product the neutral shared fill; no product a white box with a dashed border.\n */\n private product(facts: NodeFacts, palette: ProductPalette): string {\n if (facts.products.length === 0)\n return this.plain(facts, PRODUCT_NONE_FILL, DARK_TEXT, `, color=\"${PRODUCT_NONE_BORDER}\", penwidth=1.5`, 'filled,dashed');\n if (palette.sharedByAll(facts.products)) return this.plain(facts, PRODUCT_SHARED_FILL, DARK_TEXT, '');\n const colors = facts.products.map((product: string): ProductColor => palette.colorOf(product));\n if (colors.length === 1) return this.plain(facts, colors[0].color, colors[0].fontColor, '');\n return this.statement(\n facts,\n `${this.stripes(colors.map((color: ProductColor): string => color.color))}, fontcolor=\"${DARK_TEXT}\"`,\n this.labelText(facts, DARK_TEXT),\n );\n }\n\n /**\n * Runtime mode. No runtime, or one runtime with no specialization: a solid fill. One runtime with a\n * specialization: NESTED. Several runtimes: full-height stripes with the text across them (a\n * specialization on such a box shows in line 3 only).\n */\n private runtime(facts: NodeFacts): string {\n const bases = this.bases(facts.frameworks);\n if (bases.length === 0) return this.plain(facts, NO_RUNTIME_COLOR, DARK_TEXT, '');\n if (bases.length > 1)\n return this.statement(\n facts,\n `${this.stripeAttrs(bases)}, fontcolor=\"${DARK_TEXT}\"`,\n this.labelText(facts, DARK_TEXT),\n );\n const base = FRAMEWORK_STYLES[bases[0]];\n const inner = this.specialization(bases[0], facts.frameworks);\n if (inner === undefined) return this.plain(facts, base.color, base.fontColor, '');\n return this.statement(\n facts,\n `style=\"filled\", fillcolor=\"${base.color}\", fontcolor=\"${inner.fontColor}\", margin=0`,\n this.nestedTable(base.color, inner, this.labelText(facts, inner.fontColor)),\n );\n }\n\n /**\n * An outer cell in the base color whose padding is the visible frame, holding an inner ROUNDED\n * table in the specialization's color that carries the text. The node's own polygon stays its\n * FIRST shape, so the hover glow and the lock outline land on the outer box only.\n */\n private nestedTable(base: string, inner: FrameworkStyle, text: string): string {\n return (\n '<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">' +\n `<TR><TD BGCOLOR=\"${base}\" CELLPADDING=\"${NEST_PAD}\">` +\n `<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"${INNER_PAD}\" BGCOLOR=\"${inner.color}\" STYLE=\"rounded\">` +\n `<TR><TD>${text}</TD></TR></TABLE></TD></TR></TABLE>`\n );\n }\n}\n"]}
@@ -84,7 +84,7 @@ class GraphLegend {
84
84
  productRows(facts) {
85
85
  if (facts.products.length === 0)
86
86
  return this.row('no-products', this.solid(graph_products_1.PRODUCT_NONE_FILL, graph_products_1.PRODUCT_NONE_BORDER, '3 2'), 'no products declared', 'tag each project product:<name> to see each product');
87
- const palette = new graph_products_1.ProductPalette(facts.products.map((count) => count.product));
87
+ const palette = facts.palette;
88
88
  let rows = '';
89
89
  for (const count of facts.products) {
90
90
  const color = palette.colorOf(count.product);
@@ -1 +1 @@
1
- {"version":3,"file":"graph-legend.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-legend.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The architecture graph's legend, generated per color mode FROM THE PROJECTS ACTUALLY DRAWN.\n *\n * The hand-written legend this replaces listed five frameworks when six existed and never mentioned\n * the `app` and `bundle` borders the renderer drew (#1155). Generating the rows from the same tables\n * the renderer colors with (graph-color-modes.ts) means a color in use always has a row, and a color\n * nothing uses never does.\n *\n * Swatches are inline SVG drawn with presentation attributes, never `style=`, so the page carries\n * no inline CSS.\n */\n\nimport { KNOWN_FRAMEWORKS, KnownFramework } from '@webpieces/rules-sdk';\nimport {\n BASE_ORDER,\n FRAMEWORK_STYLES,\n FrameworkStyle,\n GraphMode,\n IMPACT_AFFECTED,\n IMPACT_BUILD_INPUT,\n IMPACT_BUILD_INPUT_BORDER,\n IMPACT_TOUCHED,\n IMPACT_UNTOUCHED,\n LegendFacts,\n NO_RUNTIME_COLOR,\n ProductCount,\n ROLE_STYLES,\n RoleStyle,\n} from './graph-color-modes';\nimport {\n PRODUCT_NONE_BORDER,\n PRODUCT_NONE_FILL,\n PRODUCT_SHARED_FILL,\n ProductColor,\n ProductPalette,\n} from './graph-products';\nimport type { ProductDependencyEntry } from '../configs/tag-truth-configs';\n\nconst SWATCH_W = 26;\nconst SWATCH_H = 16;\nconst FRAME = '#3a3c46';\n\nexport class GraphLegend {\n /** One section per mode; the page shows the section of the current mode and hides the rest. */\n sections(facts: LegendFacts): string {\n return (\n this.section(GraphMode.RUNTIME, this.runtimeRows(facts), false) +\n this.section(GraphMode.ARCHITECTURE, this.architectureRows(facts), true) +\n this.section(GraphMode.IMPACT, this.impactRows(), true) +\n this.section(GraphMode.PRODUCT, this.productRows(facts), true)\n );\n }\n\n /** The edge key: why a line exists. Static — every graph can carry every edge kind. */\n edgeKey(): string {\n return (\n '<div class=\"wp-legend-list\">' +\n this.edgeRow('#e9eaf0', '', 'uses', 'calls the API, or a plain library import') +\n this.edgeRow('#e9eaf0', '4 3', 'implements', 'serves the API (labeled with its contracts)') +\n this.edgeRow('#7aa2ff', '4 3', 'uses + implements', 'implements some contracts, uses others') +\n '</div>'\n );\n }\n\n private section(mode: GraphMode, rows: string, hidden: boolean): string {\n const hide = hidden ? ' hidden' : '';\n return `<div class=\"wp-legend-list\" data-wp-legend-mode=\"${mode}\"${hide}>${rows}</div>`;\n }\n\n /** Base runtimes first (stripe order), then specializations, in the shared vocabulary's order. */\n runtimeRows(facts: LegendFacts): string {\n const present = (framework: KnownFramework): boolean => facts.frameworks.includes(framework);\n const ordered: FrameworkStyle[] = [\n ...BASE_ORDER.map((base: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[base]),\n ...KNOWN_FRAMEWORKS.map((f: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[f]).filter(\n (style: FrameworkStyle): boolean => !style.isBase(),\n ),\n ];\n let rows = '';\n for (const style of ordered) {\n if (!present(style.framework)) continue;\n rows += this.row(style.framework, this.envSwatch(style), style.framework, style.description);\n }\n if (facts.multiRuntime)\n rows += this.row('multi', this.stripesSwatch(), 'several runtimes', 'one equal stripe per runtime');\n if (facts.noRuntime)\n rows += this.row('none', this.solid(NO_RUNTIME_COLOR, '', ''), 'no framework tag', 'runs nowhere declared');\n return rows;\n }\n\n architectureRows(facts: LegendFacts): string {\n let rows = '';\n for (const style of ROLE_STYLES) {\n if (!facts.roles.includes(style.role)) continue;\n rows += this.row(style.role, this.roleSwatch(style), style.role, style.description);\n }\n return rows;\n }\n\n /**\n * Which box is which is only known from the branch's sidecar, so all four rows always show. The\n * words are the Filter's (#1179): changed · dependent · dependency · not in this build.\n */\n impactRows(): string {\n return (\n this.row('touched', this.solid(IMPACT_TOUCHED, '', ''), 'changed', 'owns a changed file') +\n this.row(\n 'affected',\n this.solid(IMPACT_AFFECTED, IMPACT_TOUCHED, ''),\n 'dependent',\n 'uses a changed project: its tests and build re-run',\n ) +\n this.row(\n 'build-input',\n this.solid(IMPACT_BUILD_INPUT, IMPACT_BUILD_INPUT_BORDER, '3 2'),\n 'dependency (built, unchanged)',\n 'compiled or restored from cache for this build',\n ) +\n this.row('untouched', this.solid(IMPACT_UNTOUCHED, '', ''), 'not in this build', 'nothing here changed or depends on a change') +\n '<p class=\"wp-impact-note\" data-wp-impact-note></p>'\n );\n }\n\n /**\n * Product mode (#1179): one row per product with its counts, then the shared, several-products and\n * no-product rows that some drawn box actually uses.\n */\n productRows(facts: LegendFacts): string {\n if (facts.products.length === 0)\n return this.row(\n 'no-products',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n 'no products declared',\n 'tag each project product:<name> to see each product',\n );\n const palette = new ProductPalette(facts.products.map((count: ProductCount): string => count.product));\n let rows = '';\n for (const count of facts.products) {\n const color = palette.colorOf(count.product);\n const detail = `${count.only} only ${count.product}`;\n rows += this.row(`product:${count.product}`, this.solid(color.color, '', ''), `${count.product} · ${count.total}`, detail);\n }\n if (facts.sharedByAll > 0)\n rows += this.row(\n 'shared',\n this.solid(PRODUCT_SHARED_FILL, '', ''),\n `shared by every product · ${facts.sharedByAll}`,\n 'a change here is a change to every product',\n );\n if (facts.multiProduct)\n rows += this.row('several', this.productStripes(palette), 'several products', 'one stripe per product');\n if (facts.noProduct > 0)\n rows += this.row(\n 'no-product',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n `no product · ${facts.noProduct}`,\n 'needs a product:<name> tag',\n );\n return rows + this.boundaryRows(facts, palette);\n }\n\n /**\n * #1204: the dashed cross-product edge, and the product dependency matrix that allows each such\n * edge — `example → openapi, platform` — when the `product-tags` rule supplied one.\n */\n boundaryRows(facts: LegendFacts, palette: ProductPalette): string {\n let rows = '';\n if (facts.crossProductEdges > 0)\n rows += this.row(\n 'cross-product',\n this.line(PRODUCT_NONE_BORDER, '4 3'),\n `crosses into another product · ${facts.crossProductEdges}`,\n \"dashed, in the color of the product it depends on\",\n );\n const matrix = facts.productDependencies;\n if (matrix === null) return rows;\n const stated = matrix.filter((entry: ProductDependencyEntry): boolean => entry.allowedToDependOn.length > 0);\n if (stated.length === 0)\n return (\n rows +\n this.row(\n 'allowed-none',\n this.line(PRODUCT_NONE_BORDER, ''),\n 'no product may depend on another',\n 'product-tags.productDependencies allows no crossing',\n )\n );\n for (const entry of [...stated].sort((a: ProductDependencyEntry, b: ProductDependencyEntry): number => a.name.localeCompare(b.name)))\n rows += this.row(\n `allowed:${entry.name}`,\n this.line(palette.colorOf(entry.name).color, ''),\n `${entry.name} → ${[...entry.allowedToDependOn].sort().join(', ')}`,\n 'allowed by product-tags.productDependencies',\n );\n return rows;\n }\n\n private row(key: string, swatch: string, title: string, detail: string): string {\n return (\n `<div class=\"wp-legend-row\" data-wp-legend=\"${key}\">${swatch}` +\n `<span>${title}<small>${detail}</small></span></div>`\n );\n }\n\n private open(): string {\n return `<svg width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" viewBox=\"0 0 ${SWATCH_W} ${SWATCH_H}\" aria-hidden=\"true\">`;\n }\n\n private frame(): string {\n return `<rect x=\"0.5\" y=\"0.5\" width=\"${SWATCH_W - 1}\" height=\"${SWATCH_H - 1}\" fill=\"none\" stroke=\"${FRAME}\"/></svg>`;\n }\n\n /** A base runtime is solid; a specialization is its inset on the base color. */\n private envSwatch(style: FrameworkStyle): string {\n const base = `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[style.base].color}\"/>`;\n if (style.isBase()) return this.open() + base + this.frame();\n const inset = `<rect x=\"4\" y=\"4\" width=\"${SWATCH_W - 8}\" height=\"${SWATCH_H - 8}\" rx=\"2\" fill=\"${style.color}\"/>`;\n return this.open() + base + inset + this.frame();\n }\n\n private stripesSwatch(): string {\n const width = SWATCH_W / BASE_ORDER.length;\n const stripes = BASE_ORDER.map(\n (base: KnownFramework, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[base].color}\"/>`,\n ).join('');\n return this.open() + stripes + this.frame();\n }\n\n /** The first three product colors as stripes: the \"several products\" swatch. */\n private productStripes(palette: ProductPalette): string {\n const colors = palette.colors.slice(0, 3);\n const width = SWATCH_W / colors.length;\n const stripes = colors\n .map(\n (color: ProductColor, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${color.color}\"/>`,\n )\n .join('');\n return this.open() + stripes + this.frame();\n }\n\n private roleSwatch(style: RoleStyle): string {\n return this.solid(style.fill, '', '');\n }\n\n /** A filled swatch, optionally with an inner ring (dashed when `dash` is set). */\n private solid(fill: string, outline: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n const ring =\n outline === ''\n ? ''\n : `<rect x=\"2\" y=\"2\" width=\"${SWATCH_W - 4}\" height=\"${SWATCH_H - 4}\" fill=\"none\" stroke=\"${outline}\" stroke-width=\"2\"${dashed}/>`;\n return this.open() + `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${fill}\"/>` + ring + this.frame();\n }\n\n private edgeRow(color: string, dash: string, title: string, detail: string): string {\n return this.row(title, this.line(color, dash), title, detail);\n }\n\n /** An edge swatch: a short line, dashed when `dash` is set. */\n private line(color: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n return `<svg width=\"28\" height=\"10\" aria-hidden=\"true\"><line x1=\"0\" y1=\"5\" x2=\"28\" y2=\"5\" stroke=\"${color}\" stroke-width=\"1.6\"${dashed}/></svg>`;\n }\n}\n"]}
1
+ {"version":3,"file":"graph-legend.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-legend.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAEH,oDAAwE;AACxE,2DAc6B;AAC7B,qDAM0B;AAG1B,MAAM,QAAQ,GAAG,EAAE,CAAC;AACpB,MAAM,QAAQ,GAAG,EAAE,CAAC;AACpB,MAAM,KAAK,GAAG,SAAS,CAAC;AAExB,MAAa,WAAW;IACpB,+FAA+F;IAC/F,QAAQ,CAAC,KAAkB;QACvB,OAAO,CACH,IAAI,CAAC,OAAO,CAAC,6BAAS,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;YAC/D,IAAI,CAAC,OAAO,CAAC,6BAAS,CAAC,YAAY,EAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;YACxE,IAAI,CAAC,OAAO,CAAC,6BAAS,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC;YACvD,IAAI,CAAC,OAAO,CAAC,6BAAS,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CACjE,CAAC;IACN,CAAC;IAED,uFAAuF;IACvF,OAAO;QACH,OAAO,CACH,8BAA8B;YAC9B,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,0CAA0C,CAAC;YAC/E,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,6CAA6C,CAAC;YAC3F,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,mBAAmB,EAAE,wCAAwC,CAAC;YAC7F,QAAQ,CACX,CAAC;IACN,CAAC;IAEO,OAAO,CAAC,IAAe,EAAE,IAAY,EAAE,MAAe;QAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,OAAO,oDAAoD,IAAI,IAAI,IAAI,IAAI,IAAI,QAAQ,CAAC;IAC5F,CAAC;IAED,kGAAkG;IAClG,WAAW,CAAC,KAAkB;QAC1B,MAAM,OAAO,GAAG,CAAC,SAAyB,EAAW,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC7F,MAAM,OAAO,GAAqB;YAC9B,GAAG,8BAAU,CAAC,GAAG,CAAC,CAAC,IAAoB,EAAkB,EAAE,CAAC,oCAAgB,CAAC,IAAI,CAAC,CAAC;YACnF,GAAG,4BAAgB,CAAC,GAAG,CAAC,CAAC,CAAiB,EAAkB,EAAE,CAAC,oCAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CACtF,CAAC,KAAqB,EAAW,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CACtD;SACJ,CAAC;QACF,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;gBAAE,SAAS;YACxC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;QACjG,CAAC;QACD,IAAI,KAAK,CAAC,YAAY;YAClB,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,EAAE,kBAAkB,EAAE,8BAA8B,CAAC,CAAC;QACxG,IAAI,KAAK,CAAC,SAAS;YACf,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,oCAAgB,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,kBAAkB,EAAE,uBAAuB,CAAC,CAAC;QAChH,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,gBAAgB,CAAC,KAAkB;QAC/B,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,KAAK,MAAM,KAAK,IAAI,+BAAW,EAAE,CAAC;YAC9B,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,SAAS;YAChD,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;QACxF,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,UAAU;QACN,OAAO,CACH,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,kCAAc,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,SAAS,EAAE,qBAAqB,CAAC;YACzF,IAAI,CAAC,GAAG,CACJ,UAAU,EACV,IAAI,CAAC,KAAK,CAAC,mCAAe,EAAE,kCAAc,EAAE,EAAE,CAAC,EAC/C,WAAW,EACX,oDAAoD,CACvD;YACD,IAAI,CAAC,GAAG,CACJ,aAAa,EACb,IAAI,CAAC,KAAK,CAAC,sCAAkB,EAAE,6CAAyB,EAAE,KAAK,CAAC,EAChE,+BAA+B,EAC/B,gDAAgD,CACnD;YACD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,oCAAgB,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,mBAAmB,EAAE,6CAA6C,CAAC;YAC/H,oDAAoD,CACvD,CAAC;IACN,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,KAAkB;QAC1B,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;YAC3B,OAAO,IAAI,CAAC,GAAG,CACX,aAAa,EACb,IAAI,CAAC,KAAK,CAAC,kCAAiB,EAAE,oCAAmB,EAAE,KAAK,CAAC,EACzD,sBAAsB,EACtB,qDAAqD,CACxD,CAAC;QACN,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC9B,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,SAAS,KAAK,CAAC,OAAO,EAAE,CAAC;YACrD,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,MAAM,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;QAC/H,CAAC;QACD,IAAI,KAAK,CAAC,WAAW,GAAG,CAAC;YACrB,IAAI,IAAI,IAAI,CAAC,GAAG,CACZ,QAAQ,EACR,IAAI,CAAC,KAAK,CAAC,oCAAmB,EAAE,EAAE,EAAE,EAAE,CAAC,EACvC,6BAA6B,KAAK,CAAC,WAAW,EAAE,EAChD,4CAA4C,CAC/C,CAAC;QACN,IAAI,KAAK,CAAC,YAAY;YAClB,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,kBAAkB,EAAE,wBAAwB,CAAC,CAAC;QAC5G,IAAI,KAAK,CAAC,SAAS,GAAG,CAAC;YACnB,IAAI,IAAI,IAAI,CAAC,GAAG,CACZ,YAAY,EACZ,IAAI,CAAC,KAAK,CAAC,kCAAiB,EAAE,oCAAmB,EAAE,KAAK,CAAC,EACzD,gBAAgB,KAAK,CAAC,SAAS,EAAE,EACjC,4BAA4B,CAC/B,CAAC;QACN,OAAO,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IAED;;;OAGG;IACH,YAAY,CAAC,KAAkB,EAAE,OAAuB;QACpD,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,KAAK,CAAC,iBAAiB,GAAG,CAAC;YAC3B,IAAI,IAAI,IAAI,CAAC,GAAG,CACZ,eAAe,EACf,IAAI,CAAC,IAAI,CAAC,oCAAmB,EAAE,KAAK,CAAC,EACrC,kCAAkC,KAAK,CAAC,iBAAiB,EAAE,EAC3D,mDAAmD,CACtD,CAAC;QACN,MAAM,MAAM,GAAG,KAAK,CAAC,mBAAmB,CAAC;QACzC,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAA6B,EAAW,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC7G,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YACnB,OAAO,CACH,IAAI;gBACJ,IAAI,CAAC,GAAG,CACJ,cAAc,EACd,IAAI,CAAC,IAAI,CAAC,oCAAmB,EAAE,EAAE,CAAC,EAClC,kCAAkC,EAClC,qDAAqD,CACxD,CACJ,CAAC;QACN,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAyB,EAAE,CAAyB,EAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChI,IAAI,IAAI,IAAI,CAAC,GAAG,CACZ,WAAW,KAAK,CAAC,IAAI,EAAE,EACvB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,EAChD,GAAG,KAAK,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EACnE,6CAA6C,CAChD,CAAC;QACN,OAAO,IAAI,CAAC;IAChB,CAAC;IAEO,GAAG,CAAC,GAAW,EAAE,MAAc,EAAE,KAAa,EAAE,MAAc;QAClE,OAAO,CACH,8CAA8C,GAAG,KAAK,MAAM,EAAE;YAC9D,SAAS,KAAK,UAAU,MAAM,uBAAuB,CACxD,CAAC;IACN,CAAC;IAEO,IAAI;QACR,OAAO,eAAe,QAAQ,aAAa,QAAQ,kBAAkB,QAAQ,IAAI,QAAQ,uBAAuB,CAAC;IACrH,CAAC;IAEO,KAAK;QACT,OAAO,gCAAgC,QAAQ,GAAG,CAAC,aAAa,QAAQ,GAAG,CAAC,yBAAyB,KAAK,WAAW,CAAC;IAC1H,CAAC;IAED,gFAAgF;IACxE,SAAS,CAAC,KAAqB;QACnC,MAAM,IAAI,GAAG,gBAAgB,QAAQ,aAAa,QAAQ,WAAW,oCAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC;QAC7G,IAAI,KAAK,CAAC,MAAM,EAAE;YAAE,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC7D,MAAM,KAAK,GAAG,4BAA4B,QAAQ,GAAG,CAAC,aAAa,QAAQ,GAAG,CAAC,kBAAkB,KAAK,CAAC,KAAK,KAAK,CAAC;QAClH,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IACrD,CAAC;IAEO,aAAa;QACjB,MAAM,KAAK,GAAG,QAAQ,GAAG,8BAAU,CAAC,MAAM,CAAC;QAC3C,MAAM,OAAO,GAAG,8BAAU,CAAC,GAAG,CAC1B,CAAC,IAAoB,EAAE,KAAa,EAAU,EAAE,CAC5C,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,QAAQ,WAAW,oCAAgB,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,CAC1I,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACX,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAChD,CAAC;IAED,gFAAgF;IACxE,cAAc,CAAC,OAAuB;QAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;QACvC,MAAM,OAAO,GAAG,MAAM;aACjB,GAAG,CACA,CAAC,KAAmB,EAAE,KAAa,EAAU,EAAE,CAC3C,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,QAAQ,WAAW,KAAK,CAAC,KAAK,KAAK,CACzH;aACA,IAAI,CAAC,EAAE,CAAC,CAAC;QACd,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAChD,CAAC;IAEO,UAAU,CAAC,KAAgB;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,kFAAkF;IAC1E,KAAK,CAAC,IAAY,EAAE,OAAe,EAAE,IAAY;QACrD,MAAM,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,IAAI,GAAG,CAAC;QAChE,MAAM,IAAI,GACN,OAAO,KAAK,EAAE;YACV,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,4BAA4B,QAAQ,GAAG,CAAC,aAAa,QAAQ,GAAG,CAAC,yBAAyB,OAAO,qBAAqB,MAAM,IAAI,CAAC;QAC3I,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,gBAAgB,QAAQ,aAAa,QAAQ,WAAW,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IACjH,CAAC;IAEO,OAAO,CAAC,KAAa,EAAE,IAAY,EAAE,KAAa,EAAE,MAAc;QACtE,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAClE,CAAC;IAED,+DAA+D;IACvD,IAAI,CAAC,KAAa,EAAE,IAAY;QACpC,MAAM,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,IAAI,GAAG,CAAC;QAChE,OAAO,6FAA6F,KAAK,uBAAuB,MAAM,UAAU,CAAC;IACrJ,CAAC;CACJ;AA/ND,kCA+NC","sourcesContent":["/**\n * The architecture graph's legend, generated per color mode FROM THE PROJECTS ACTUALLY DRAWN.\n *\n * The hand-written legend this replaces listed five frameworks when six existed and never mentioned\n * the `app` and `bundle` borders the renderer drew (#1155). Generating the rows from the same tables\n * the renderer colors with (graph-color-modes.ts) means a color in use always has a row, and a color\n * nothing uses never does.\n *\n * Swatches are inline SVG drawn with presentation attributes, never `style=`, so the page carries\n * no inline CSS.\n */\n\nimport { KNOWN_FRAMEWORKS, KnownFramework } from '@webpieces/rules-sdk';\nimport {\n BASE_ORDER,\n FRAMEWORK_STYLES,\n FrameworkStyle,\n GraphMode,\n IMPACT_AFFECTED,\n IMPACT_BUILD_INPUT,\n IMPACT_BUILD_INPUT_BORDER,\n IMPACT_TOUCHED,\n IMPACT_UNTOUCHED,\n LegendFacts,\n NO_RUNTIME_COLOR,\n ROLE_STYLES,\n RoleStyle,\n} from './graph-color-modes';\nimport {\n PRODUCT_NONE_BORDER,\n PRODUCT_NONE_FILL,\n PRODUCT_SHARED_FILL,\n ProductColor,\n ProductPalette,\n} from './graph-products';\nimport type { ProductDependencyEntry } from '../configs/tag-truth-configs';\n\nconst SWATCH_W = 26;\nconst SWATCH_H = 16;\nconst FRAME = '#3a3c46';\n\nexport class GraphLegend {\n /** One section per mode; the page shows the section of the current mode and hides the rest. */\n sections(facts: LegendFacts): string {\n return (\n this.section(GraphMode.RUNTIME, this.runtimeRows(facts), false) +\n this.section(GraphMode.ARCHITECTURE, this.architectureRows(facts), true) +\n this.section(GraphMode.IMPACT, this.impactRows(), true) +\n this.section(GraphMode.PRODUCT, this.productRows(facts), true)\n );\n }\n\n /** The edge key: why a line exists. Static — every graph can carry every edge kind. */\n edgeKey(): string {\n return (\n '<div class=\"wp-legend-list\">' +\n this.edgeRow('#e9eaf0', '', 'uses', 'calls the API, or a plain library import') +\n this.edgeRow('#e9eaf0', '4 3', 'implements', 'serves the API (labeled with its contracts)') +\n this.edgeRow('#7aa2ff', '4 3', 'uses + implements', 'implements some contracts, uses others') +\n '</div>'\n );\n }\n\n private section(mode: GraphMode, rows: string, hidden: boolean): string {\n const hide = hidden ? ' hidden' : '';\n return `<div class=\"wp-legend-list\" data-wp-legend-mode=\"${mode}\"${hide}>${rows}</div>`;\n }\n\n /** Base runtimes first (stripe order), then specializations, in the shared vocabulary's order. */\n runtimeRows(facts: LegendFacts): string {\n const present = (framework: KnownFramework): boolean => facts.frameworks.includes(framework);\n const ordered: FrameworkStyle[] = [\n ...BASE_ORDER.map((base: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[base]),\n ...KNOWN_FRAMEWORKS.map((f: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[f]).filter(\n (style: FrameworkStyle): boolean => !style.isBase(),\n ),\n ];\n let rows = '';\n for (const style of ordered) {\n if (!present(style.framework)) continue;\n rows += this.row(style.framework, this.envSwatch(style), style.framework, style.description);\n }\n if (facts.multiRuntime)\n rows += this.row('multi', this.stripesSwatch(), 'several runtimes', 'one equal stripe per runtime');\n if (facts.noRuntime)\n rows += this.row('none', this.solid(NO_RUNTIME_COLOR, '', ''), 'no framework tag', 'runs nowhere declared');\n return rows;\n }\n\n architectureRows(facts: LegendFacts): string {\n let rows = '';\n for (const style of ROLE_STYLES) {\n if (!facts.roles.includes(style.role)) continue;\n rows += this.row(style.role, this.roleSwatch(style), style.role, style.description);\n }\n return rows;\n }\n\n /**\n * Which box is which is only known from the branch's sidecar, so all four rows always show. The\n * words are the Filter's (#1179): changed · dependent · dependency · not in this build.\n */\n impactRows(): string {\n return (\n this.row('touched', this.solid(IMPACT_TOUCHED, '', ''), 'changed', 'owns a changed file') +\n this.row(\n 'affected',\n this.solid(IMPACT_AFFECTED, IMPACT_TOUCHED, ''),\n 'dependent',\n 'uses a changed project: its tests and build re-run',\n ) +\n this.row(\n 'build-input',\n this.solid(IMPACT_BUILD_INPUT, IMPACT_BUILD_INPUT_BORDER, '3 2'),\n 'dependency (built, unchanged)',\n 'compiled or restored from cache for this build',\n ) +\n this.row('untouched', this.solid(IMPACT_UNTOUCHED, '', ''), 'not in this build', 'nothing here changed or depends on a change') +\n '<p class=\"wp-impact-note\" data-wp-impact-note></p>'\n );\n }\n\n /**\n * Product mode (#1179): one row per product with its counts, then the shared, several-products and\n * no-product rows that some drawn box actually uses.\n */\n productRows(facts: LegendFacts): string {\n if (facts.products.length === 0)\n return this.row(\n 'no-products',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n 'no products declared',\n 'tag each project product:<name> to see each product',\n );\n const palette = facts.palette;\n let rows = '';\n for (const count of facts.products) {\n const color = palette.colorOf(count.product);\n const detail = `${count.only} only ${count.product}`;\n rows += this.row(`product:${count.product}`, this.solid(color.color, '', ''), `${count.product} · ${count.total}`, detail);\n }\n if (facts.sharedByAll > 0)\n rows += this.row(\n 'shared',\n this.solid(PRODUCT_SHARED_FILL, '', ''),\n `shared by every product · ${facts.sharedByAll}`,\n 'a change here is a change to every product',\n );\n if (facts.multiProduct)\n rows += this.row('several', this.productStripes(palette), 'several products', 'one stripe per product');\n if (facts.noProduct > 0)\n rows += this.row(\n 'no-product',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n `no product · ${facts.noProduct}`,\n 'needs a product:<name> tag',\n );\n return rows + this.boundaryRows(facts, palette);\n }\n\n /**\n * #1204: the dashed cross-product edge, and the product dependency matrix that allows each such\n * edge — `example → openapi, platform` — when the `product-tags` rule supplied one.\n */\n boundaryRows(facts: LegendFacts, palette: ProductPalette): string {\n let rows = '';\n if (facts.crossProductEdges > 0)\n rows += this.row(\n 'cross-product',\n this.line(PRODUCT_NONE_BORDER, '4 3'),\n `crosses into another product · ${facts.crossProductEdges}`,\n \"dashed, in the color of the product it depends on\",\n );\n const matrix = facts.productDependencies;\n if (matrix === null) return rows;\n const stated = matrix.filter((entry: ProductDependencyEntry): boolean => entry.allowedToDependOn.length > 0);\n if (stated.length === 0)\n return (\n rows +\n this.row(\n 'allowed-none',\n this.line(PRODUCT_NONE_BORDER, ''),\n 'no product may depend on another',\n 'product-tags.productDependencies allows no crossing',\n )\n );\n for (const entry of [...stated].sort((a: ProductDependencyEntry, b: ProductDependencyEntry): number => a.name.localeCompare(b.name)))\n rows += this.row(\n `allowed:${entry.name}`,\n this.line(palette.colorOf(entry.name).color, ''),\n `${entry.name} → ${[...entry.allowedToDependOn].sort().join(', ')}`,\n 'allowed by product-tags.productDependencies',\n );\n return rows;\n }\n\n private row(key: string, swatch: string, title: string, detail: string): string {\n return (\n `<div class=\"wp-legend-row\" data-wp-legend=\"${key}\">${swatch}` +\n `<span>${title}<small>${detail}</small></span></div>`\n );\n }\n\n private open(): string {\n return `<svg width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" viewBox=\"0 0 ${SWATCH_W} ${SWATCH_H}\" aria-hidden=\"true\">`;\n }\n\n private frame(): string {\n return `<rect x=\"0.5\" y=\"0.5\" width=\"${SWATCH_W - 1}\" height=\"${SWATCH_H - 1}\" fill=\"none\" stroke=\"${FRAME}\"/></svg>`;\n }\n\n /** A base runtime is solid; a specialization is its inset on the base color. */\n private envSwatch(style: FrameworkStyle): string {\n const base = `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[style.base].color}\"/>`;\n if (style.isBase()) return this.open() + base + this.frame();\n const inset = `<rect x=\"4\" y=\"4\" width=\"${SWATCH_W - 8}\" height=\"${SWATCH_H - 8}\" rx=\"2\" fill=\"${style.color}\"/>`;\n return this.open() + base + inset + this.frame();\n }\n\n private stripesSwatch(): string {\n const width = SWATCH_W / BASE_ORDER.length;\n const stripes = BASE_ORDER.map(\n (base: KnownFramework, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[base].color}\"/>`,\n ).join('');\n return this.open() + stripes + this.frame();\n }\n\n /** The first three product colors as stripes: the \"several products\" swatch. */\n private productStripes(palette: ProductPalette): string {\n const colors = palette.colors.slice(0, 3);\n const width = SWATCH_W / colors.length;\n const stripes = colors\n .map(\n (color: ProductColor, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${color.color}\"/>`,\n )\n .join('');\n return this.open() + stripes + this.frame();\n }\n\n private roleSwatch(style: RoleStyle): string {\n return this.solid(style.fill, '', '');\n }\n\n /** A filled swatch, optionally with an inner ring (dashed when `dash` is set). */\n private solid(fill: string, outline: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n const ring =\n outline === ''\n ? ''\n : `<rect x=\"2\" y=\"2\" width=\"${SWATCH_W - 4}\" height=\"${SWATCH_H - 4}\" fill=\"none\" stroke=\"${outline}\" stroke-width=\"2\"${dashed}/>`;\n return this.open() + `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${fill}\"/>` + ring + this.frame();\n }\n\n private edgeRow(color: string, dash: string, title: string, detail: string): string {\n return this.row(title, this.line(color, dash), title, detail);\n }\n\n /** An edge swatch: a short line, dashed when `dash` is set. */\n private line(color: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n return `<svg width=\"28\" height=\"10\" aria-hidden=\"true\"><line x1=\"0\" y1=\"5\" x2=\"28\" y2=\"5\" stroke=\"${color}\" stroke-width=\"1.6\"${dashed}/></svg>`;\n }\n}\n"]}
@@ -10,6 +10,7 @@
10
10
  * Markup only. Behaviour is graph-visualizer.client.ts; styling is graph-page-styles.ts. No element
11
11
  * carries a `style=` attribute — every look is a class.
12
12
  */
13
+ import { ProductColor } from './graph-products';
13
14
  /**
14
15
  * The Filter popover's "Changes on this branch" choices. The page computes each set from the Impact
15
16
  * sidecar (graph-impact.ts): CHANGED = touched; DEPENDENTS = touched + affected (nx affected: their
@@ -48,15 +49,21 @@ export declare class ShellParts {
48
49
  readonly filterStatus: string;
49
50
  readonly snapshot: string;
50
51
  readonly responsibilities: string;
51
- /** Every declared product, sorted (#1179); empty hides the Filter's Product group. */
52
- readonly products: string[];
52
+ /**
53
+ * One chip per product (#1179), sorted, each colored from the page's ONE palette (#1244);
54
+ * empty hides the Filter's Product group.
55
+ */
56
+ readonly products: ProductColor[];
53
57
  readonly runtime: boolean;
54
58
  readonly frameworks: readonly string[];
55
59
  readonly roles: readonly string[];
56
60
  readonly emptyState: string;
57
61
  constructor(title: string, lockControl: string, legend: string, edgeKey: string, filterStatus: string, snapshot: string, responsibilities: string,
58
- /** Every declared product, sorted (#1179); empty hides the Filter's Product group. */
59
- products: string[], runtime?: boolean, frameworks?: readonly string[], roles?: readonly string[], emptyState?: string);
62
+ /**
63
+ * One chip per product (#1179), sorted, each colored from the page's ONE palette (#1244);
64
+ * empty hides the Filter's Product group.
65
+ */
66
+ products: ProductColor[], runtime?: boolean, frameworks?: readonly string[], roles?: readonly string[], emptyState?: string);
60
67
  }
61
68
  export declare class GraphPageShell {
62
69
  body(parts: ShellParts): string;