@webpieces/nx-webpieces-rules 0.3.128 → 0.3.130

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/executors.json CHANGED
@@ -119,6 +119,11 @@
119
119
  "implementation": "./src/executors/validate-eslint-sync/executor",
120
120
  "schema": "./src/executors/validate-eslint-sync/schema.json",
121
121
  "description": "Validate that workspace and template eslint.webpieces.config.mjs files have identical rules"
122
+ },
123
+ "validate-nx-wiring": {
124
+ "implementation": "./src/executors/validate-nx-wiring/executor",
125
+ "schema": "./src/executors/validate-nx-wiring/schema.json",
126
+ "description": "Validate the webpieces validators are wired into the build via nx.json targetDefaults dependsOn"
122
127
  }
123
128
  }
124
129
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/nx-webpieces-rules",
3
- "version": "0.3.128",
3
+ "version": "0.3.130",
4
4
  "description": "Nx-specific webpieces validation rules and graph tooling. Bundles all @webpieces rule packages with Nx graph validators and an inference plugin.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -18,10 +18,10 @@
18
18
  "README.md"
19
19
  ],
20
20
  "dependencies": {
21
- "@webpieces/ai-hook-rules": "0.3.128",
22
- "@webpieces/code-rules": "0.3.128",
23
- "@webpieces/eslint-rules": "0.3.128",
24
- "@webpieces/rules-config": "0.3.128"
21
+ "@webpieces/ai-hook-rules": "0.3.130",
22
+ "@webpieces/code-rules": "0.3.130",
23
+ "@webpieces/eslint-rules": "0.3.130",
24
+ "@webpieces/rules-config": "0.3.130"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "@nx/devkit": ">=18.0.0"
@@ -19,12 +19,12 @@ async function runExecutor(options, context) {
19
19
  console.log('\nšŸ“Š Architecture Graph Generator\n');
20
20
  // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
21
21
  try {
22
- // Step 1: Generate current graph from project.json files
23
- console.log('šŸ“Š Generating dependency graph from project.json files...');
24
- const rawGraph = await (0, graph_generator_1.generateGraph)();
22
+ // Step 1: Build the full graph from nx, then transitively reduce it to the view
23
+ console.log("šŸ“Š Generating dependency graph from nx's project graph...");
24
+ const reducedGraph = await (0, graph_generator_1.generateReducedGraph)();
25
25
  // Step 2: Topological sort (to assign levels for visualization)
26
26
  console.log('šŸ”„ Computing topological layers...');
27
- const enhancedGraph = (0, graph_sorter_1.sortGraphTopologically)(rawGraph);
27
+ const enhancedGraph = (0, graph_sorter_1.sortGraphTopologically)(reducedGraph);
28
28
  // Step 3: Save the graph
29
29
  console.log('šŸ’¾ Saving graph to architecture/dependencies.json...');
30
30
  (0, graph_loader_1.saveGraph)(enhancedGraph, workspaceRoot, graphPath);
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/generate/executor.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;AAgBH,8BAqCC;AAlDD,+DAA0D;AAC1D,yDAAgE;AAChE,yDAAmD;AACnD,2CAAwC;AAUzB,KAAK,UAAU,WAAW,CACrC,OAAgC,EAChC,OAAwB;IAExB,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACpC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAEnC,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IAEnD,8DAA8D;IAC9D,IAAI,CAAC;QACD,yDAAyD;QACzD,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACzE,MAAM,QAAQ,GAAG,MAAM,IAAA,+BAAa,GAAE,CAAC;QAEvC,gEAAgE;QAChE,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;QAClD,MAAM,aAAa,GAAG,IAAA,qCAAsB,EAAC,QAAQ,CAAC,CAAC;QAEvD,yBAAyB;QACzB,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;QACpE,IAAA,wBAAS,EAAC,aAAa,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAE1C,gBAAgB;QAChB,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC;QACvD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,gBAAgB,YAAY,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAEpE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,IAAA,iBAAO,EAAC,GAAG,CAAC,CAAC;QAC3B,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;AACL,CAAC","sourcesContent":["/**\n * Generate Executor\n *\n * Generates the architecture dependency graph and saves it to architecture/dependencies.json.\n *\n * Usage:\n * nx run architecture:generate\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { generateGraph } from '../../lib/graph-generator';\nimport { sortGraphTopologically } from '../../lib/graph-sorter';\nimport { saveGraph } from '../../lib/graph-loader';\nimport { toError } from '../../toError';\n\nexport interface GenerateExecutorOptions {\n graphPath?: string;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nexport default async function runExecutor(\n options: GenerateExecutorOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const graphPath = options.graphPath;\n const workspaceRoot = context.root;\n\n console.log('\\nšŸ“Š Architecture Graph Generator\\n');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Step 1: Generate current graph from project.json files\n console.log('šŸ“Š Generating dependency graph from project.json files...');\n const rawGraph = await generateGraph();\n\n // Step 2: Topological sort (to assign levels for visualization)\n console.log('šŸ”„ Computing topological layers...');\n const enhancedGraph = sortGraphTopologically(rawGraph);\n\n // Step 3: Save the graph\n console.log('šŸ’¾ Saving graph to architecture/dependencies.json...');\n saveGraph(enhancedGraph, workspaceRoot, graphPath);\n console.log('āœ… Graph saved successfully');\n\n // Print summary\n const projectCount = Object.keys(enhancedGraph).length;\n const levels = new Set(Object.values(enhancedGraph).map((e) => e.level));\n console.log(`\\nšŸ“ˆ Graph Summary:`);\n console.log(` Projects: ${projectCount}`);\n console.log(` Levels: ${levels.size} (0-${Math.max(...levels)})`);\n\n return { success: true };\n } catch (err: unknown) {\n const error = toError(err);\n console.error('āŒ Graph generation failed:', error.message);\n return { success: false };\n }\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/generate/executor.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;AAgBH,8BAqCC;AAlDD,+DAAiE;AACjE,yDAAgE;AAChE,yDAAmD;AACnD,2CAAwC;AAUzB,KAAK,UAAU,WAAW,CACrC,OAAgC,EAChC,OAAwB;IAExB,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACpC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAEnC,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IAEnD,8DAA8D;IAC9D,IAAI,CAAC;QACD,gFAAgF;QAChF,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACzE,MAAM,YAAY,GAAG,MAAM,IAAA,sCAAoB,GAAE,CAAC;QAElD,gEAAgE;QAChE,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;QAClD,MAAM,aAAa,GAAG,IAAA,qCAAsB,EAAC,YAAY,CAAC,CAAC;QAE3D,yBAAyB;QACzB,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;QACpE,IAAA,wBAAS,EAAC,aAAa,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAE1C,gBAAgB;QAChB,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC;QACvD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,gBAAgB,YAAY,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAEpE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,IAAA,iBAAO,EAAC,GAAG,CAAC,CAAC;QAC3B,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;AACL,CAAC","sourcesContent":["/**\n * Generate Executor\n *\n * Generates the architecture dependency graph and saves it to architecture/dependencies.json.\n *\n * Usage:\n * nx run architecture:generate\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { generateReducedGraph } from '../../lib/graph-generator';\nimport { sortGraphTopologically } from '../../lib/graph-sorter';\nimport { saveGraph } from '../../lib/graph-loader';\nimport { toError } from '../../toError';\n\nexport interface GenerateExecutorOptions {\n graphPath?: string;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nexport default async function runExecutor(\n options: GenerateExecutorOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const graphPath = options.graphPath;\n const workspaceRoot = context.root;\n\n console.log('\\nšŸ“Š Architecture Graph Generator\\n');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Step 1: Build the full graph from nx, then transitively reduce it to the view\n console.log(\"šŸ“Š Generating dependency graph from nx's project graph...\");\n const reducedGraph = await generateReducedGraph();\n\n // Step 2: Topological sort (to assign levels for visualization)\n console.log('šŸ”„ Computing topological layers...');\n const enhancedGraph = sortGraphTopologically(reducedGraph);\n\n // Step 3: Save the graph\n console.log('šŸ’¾ Saving graph to architecture/dependencies.json...');\n saveGraph(enhancedGraph, workspaceRoot, graphPath);\n console.log('āœ… Graph saved successfully');\n\n // Print summary\n const projectCount = Object.keys(enhancedGraph).length;\n const levels = new Set(Object.values(enhancedGraph).map((e) => e.level));\n console.log(`\\nšŸ“ˆ Graph Summary:`);\n console.log(` Projects: ${projectCount}`);\n console.log(` Levels: ${levels.size} (0-${Math.max(...levels)})`);\n\n return { success: true };\n } catch (err: unknown) {\n const error = toError(err);\n console.error('āŒ Graph generation failed:', error.message);\n return { success: false };\n }\n}\n"]}
@@ -42,12 +42,12 @@ async function runExecutor(options, context) {
42
42
  console.error(' 4. Commit architecture/dependencies.json');
43
43
  return { success: false };
44
44
  }
45
- // Step 1: Generate current graph from project.json files
45
+ // Step 1: Build the full graph from nx, then transitively reduce it
46
46
  console.log('šŸ“Š Generating current dependency graph...');
47
- const rawGraph = await (0, graph_generator_1.generateGraph)();
47
+ const reducedGraph = await (0, graph_generator_1.generateReducedGraph)();
48
48
  // Step 2: Topological sort (to get enhanced graph with levels)
49
49
  console.log('šŸ”„ Computing topological layers...');
50
- const currentGraph = (0, graph_sorter_1.sortGraphTopologically)(rawGraph);
50
+ const currentGraph = (0, graph_sorter_1.sortGraphTopologically)(reducedGraph);
51
51
  // Step 3: Load saved graph
52
52
  console.log('šŸ“‚ Loading saved graph...');
53
53
  const savedGraph = (0, graph_loader_1.loadBlessedGraph)(workspaceRoot, graphPath);
@@ -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 { writeTemplate } from '@webpieces/rules-config';\nimport { generateGraph } from '../../lib/graph-generator';\nimport { sortGraphTopologically } from '../../lib/graph-sorter';\nimport { compareGraphs } from '../../lib/graph-comparator';\nimport { loadBlessedGraph, graphFileExists } from '../../lib/graph-loader';\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\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 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 console.error('āŒ No saved graph found at architecture/dependencies.json');\n console.error('');\n console.error('To initialize:');\n console.error(' 1. Run: nx run architecture:generate');\n console.error(' 2. Run: nx run architecture:visualize');\n console.error(' 3. Manually inspect the generated graph to confirm it is the desired architecture');\n console.error(' 4. Commit architecture/dependencies.json');\n return { success: false };\n }\n\n // Step 1: Generate current graph from project.json files\n console.log('šŸ“Š Generating current dependency graph...');\n const rawGraph = await generateGraph();\n\n // Step 2: Topological sort (to get enhanced graph with levels)\n console.log('šŸ”„ Computing topological layers...');\n const currentGraph = sortGraphTopologically(rawGraph);\n\n // Step 3: 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 4: Compare graphs\n console.log('šŸ” Comparing current graph to saved graph...');\n const comparison = compareGraphs(currentGraph, savedGraph);\n\n if (comparison.identical) {\n console.log('āœ… Architecture unchanged - current graph matches saved graph');\n return { success: true };\n } else {\n // Write instructions file for AI agent\n const mdPath = writeTmpInstructionsFile(workspaceRoot);\n\n console.error('āŒ Architecture has changed since last update!');\n console.error('\\nDifferences:');\n console.error(comparison.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(' 2. If intentional, ASK USER to run: nx run architecture:generate since this is a critical change');\n console.error(' 3. Commit the updated architecture/dependencies.json');\n return { success: false };\n }\n } catch (err: unknown) {\n const error = toError(err);\n console.error('āŒ Architecture validation failed:', error.message);\n return { success: false };\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 { writeTemplate } 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 { 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\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 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 console.error('āŒ No saved graph found at architecture/dependencies.json');\n console.error('');\n console.error('To initialize:');\n console.error(' 1. Run: nx run architecture:generate');\n console.error(' 2. Run: nx run architecture:visualize');\n console.error(' 3. Manually inspect the generated graph to confirm it is the desired architecture');\n console.error(' 4. Commit architecture/dependencies.json');\n return { success: false };\n }\n\n // Step 1: Build the full graph from nx, then transitively reduce it\n console.log('šŸ“Š Generating current dependency graph...');\n const reducedGraph = await generateReducedGraph();\n\n // Step 2: Topological sort (to get enhanced graph with levels)\n console.log('šŸ”„ Computing topological layers...');\n const currentGraph = sortGraphTopologically(reducedGraph);\n\n // Step 3: 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 4: Compare graphs\n console.log('šŸ” Comparing current graph to saved graph...');\n const comparison = compareGraphs(currentGraph, savedGraph);\n\n if (comparison.identical) {\n console.log('āœ… Architecture unchanged - current graph matches saved graph');\n return { success: true };\n } else {\n // Write instructions file for AI agent\n const mdPath = writeTmpInstructionsFile(workspaceRoot);\n\n console.error('āŒ Architecture has changed since last update!');\n console.error('\\nDifferences:');\n console.error(comparison.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(' 2. If intentional, ASK USER to run: nx run architecture:generate since this is a critical change');\n console.error(' 3. Commit the updated architecture/dependencies.json');\n return { success: false };\n }\n } catch (err: unknown) {\n const error = toError(err);\n console.error('āŒ Architecture validation failed:', error.message);\n return { success: false };\n }\n}\n"]}
@@ -1,11 +1,17 @@
1
1
  /**
2
- * Validate No Skip-Level Dependencies Executor
2
+ * Validate No Skip-Level Dependencies Executor — RETIRED (no-op).
3
3
  *
4
- * Validates that no project has redundant transitive dependencies.
5
- * If project A depends on B, and B transitively brings in C, then A should NOT
6
- * also directly depend on C (it's redundant and clutters the dependency graph).
4
+ * Skip-level (redundant transitive) edges used to be an error here. That is no longer
5
+ * meaningful: `architecture:generate` now derives the graph from nx's project graph and
6
+ * applies transitive reduction, so the committed architecture/dependencies.json can never
7
+ * contain a redundant edge. The check is superseded by auto-reduction.
7
8
  *
8
- * This keeps the architecture graph clean for visualization and human understanding.
9
+ * Worse, its old remediation told users to remove "redundant" deps from package.json —
10
+ * which is exactly the runtime-validity trap (a transitively-reachable package.json entry
11
+ * can still be a real runtime dependency, e.g. a peerDependency or generated client).
12
+ *
13
+ * Defaults off (workspace.validations.noSkipLevelDeps=false). Kept as a no-op for one
14
+ * release so any explicit enablement does not error on now-expected skip-level edges.
9
15
  *
10
16
  * Usage:
11
17
  * nx run architecture:validate-no-skiplevel-deps
@@ -16,4 +22,4 @@ export interface ValidateNoSkipLevelDepsOptions {
16
22
  export interface ExecutorResult {
17
23
  success: boolean;
18
24
  }
19
- export default function runExecutor(_options: ValidateNoSkipLevelDepsOptions, context: ExecutorContext): Promise<ExecutorResult>;
25
+ export default function runExecutor(_options: ValidateNoSkipLevelDepsOptions, _context: ExecutorContext): Promise<ExecutorResult>;
@@ -1,125 +1,28 @@
1
1
  "use strict";
2
2
  /**
3
- * Validate No Skip-Level Dependencies Executor
3
+ * Validate No Skip-Level Dependencies Executor — RETIRED (no-op).
4
4
  *
5
- * Validates that no project has redundant transitive dependencies.
6
- * If project A depends on B, and B transitively brings in C, then A should NOT
7
- * also directly depend on C (it's redundant and clutters the dependency graph).
5
+ * Skip-level (redundant transitive) edges used to be an error here. That is no longer
6
+ * meaningful: `architecture:generate` now derives the graph from nx's project graph and
7
+ * applies transitive reduction, so the committed architecture/dependencies.json can never
8
+ * contain a redundant edge. The check is superseded by auto-reduction.
8
9
  *
9
- * This keeps the architecture graph clean for visualization and human understanding.
10
+ * Worse, its old remediation told users to remove "redundant" deps from package.json —
11
+ * which is exactly the runtime-validity trap (a transitively-reachable package.json entry
12
+ * can still be a real runtime dependency, e.g. a peerDependency or generated client).
13
+ *
14
+ * Defaults off (workspace.validations.noSkipLevelDeps=false). Kept as a no-op for one
15
+ * release so any explicit enablement does not error on now-expected skip-level edges.
10
16
  *
11
17
  * Usage:
12
18
  * nx run architecture:validate-no-skiplevel-deps
13
19
  */
14
20
  Object.defineProperty(exports, "__esModule", { value: true });
15
21
  exports.default = runExecutor;
16
- const graph_generator_1 = require("../../lib/graph-generator");
17
- const rules_config_1 = require("@webpieces/rules-config");
18
- const toError_1 = require("../../toError");
19
- /**
20
- * Compute all transitive dependencies for a project
21
- */
22
- function computeTransitiveDeps(project, graph, visited = new Set()) {
23
- const result = new Set();
24
- if (visited.has(project)) {
25
- return result;
26
- }
27
- visited.add(project);
28
- const directDeps = graph[project] || [];
29
- for (const dep of directDeps) {
30
- result.add(dep);
31
- // Recursively get transitive deps
32
- const transitive = computeTransitiveDeps(dep, graph, visited);
33
- for (const t of transitive) {
34
- result.add(t);
35
- }
36
- }
37
- return result;
38
- }
39
- /**
40
- * Find redundant dependencies for a project
41
- */
42
- function findRedundantDeps(project, graph) {
43
- const redundant = [];
44
- const directDeps = graph[project] || [];
45
- // For each direct dependency, compute what it transitively brings in
46
- const transitiveByDep = new Map();
47
- for (const dep of directDeps) {
48
- transitiveByDep.set(dep, computeTransitiveDeps(dep, graph));
49
- }
50
- // Check if any direct dependency is already brought in by another
51
- const transitiveEntries = Array.from(transitiveByDep.entries());
52
- for (const dep of directDeps) {
53
- for (const entry of transitiveEntries) {
54
- const otherDep = entry[0];
55
- const otherTransitive = entry[1];
56
- if (otherDep !== dep && otherTransitive.has(dep)) {
57
- redundant.push({
58
- project,
59
- redundantDep: dep,
60
- alreadyBroughtInBy: otherDep,
61
- });
62
- break; // Only report once per redundant dep
63
- }
64
- }
65
- }
66
- return redundant;
67
- }
68
- /**
69
- * Write documentation file when violations are found
70
- */
71
- function writeDocFile(workspaceRoot) {
72
- // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
73
- try {
74
- (0, rules_config_1.writeTemplate)(workspaceRoot, 'webpieces.transitivedeps.md');
75
- }
76
- catch (err) {
77
- const error = (0, toError_1.toError)(err);
78
- console.warn('Could not write webpieces.transitivedeps.md:', error.message);
79
- }
80
- }
81
- async function runExecutor(_options, context) {
82
- console.log('\nšŸ”„ Validating No Skip-Level Dependencies\n');
83
- // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
84
- try {
85
- // Step 1: Generate current graph from project.json files
86
- console.log('šŸ“Š Generating dependency graph from project.json files...');
87
- const graph = await (0, graph_generator_1.generateGraph)();
88
- // Step 2: Find all redundant dependencies
89
- console.log('šŸ” Checking for redundant transitive dependencies...');
90
- const allRedundant = [];
91
- for (const project of Object.keys(graph)) {
92
- const redundant = findRedundantDeps(project, graph);
93
- allRedundant.push(...redundant);
94
- }
95
- if (allRedundant.length === 0) {
96
- console.log('āœ… No redundant transitive dependencies detected!');
97
- console.log('\nšŸ“ˆ Graph is clean and minimal.');
98
- return { success: true };
99
- }
100
- // Write documentation file
101
- const workspaceRoot = context.root || process.cwd();
102
- writeDocFile(workspaceRoot);
103
- // Report violations
104
- console.error('\nāŒ Redundant transitive dependencies detected!\n');
105
- console.error('āš ļø AI Agent: READ .webpieces/instruct-ai/webpieces.transitivedeps.md for fix instructions!\n');
106
- for (const r of allRedundant) {
107
- console.error(` ${r.project}:`);
108
- console.error(` └─ "${r.redundantDep}" is REDUNDANT`);
109
- console.error(` (already brought in by "${r.alreadyBroughtInBy}")\n`);
110
- }
111
- console.error('\nTo fix:');
112
- console.error(' 1. READ .webpieces/instruct-ai/webpieces.transitivedeps.md');
113
- console.error(' 2. Remove redundant deps from project.json build.dependsOn');
114
- console.error(' 3. Remove redundant deps from package.json dependencies');
115
- console.error(' 4. Run: npx nx run architecture:generate');
116
- console.error(' 5. Run: npm run build-all');
117
- return { success: false };
118
- }
119
- catch (err) {
120
- const error = (0, toError_1.toError)(err);
121
- console.error('āŒ Skip-level validation failed:', error.message);
122
- return { success: false };
123
- }
22
+ async function runExecutor(_options, _context) {
23
+ console.log('\nā­ļø validate-no-skiplevel-deps is retired (no-op).\n' +
24
+ ' Superseded by auto-reduction in `architecture:generate`: the committed graph is\n' +
25
+ ' transitively reduced, so skip-level edges cannot occur.\n');
26
+ return { success: true };
124
27
  }
125
28
  //# sourceMappingURL=executor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-no-skiplevel-deps/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Skip-Level Dependencies Executor\n *\n * Validates that no project has redundant transitive dependencies.\n * If project A depends on B, and B transitively brings in C, then A should NOT\n * also directly depend on C (it's redundant and clutters the dependency graph).\n *\n * This keeps the architecture graph clean for visualization and human understanding.\n *\n * Usage:\n * nx run architecture:validate-no-skiplevel-deps\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { generateGraph } from '../../lib/graph-generator';\nimport { writeTemplate } from '@webpieces/rules-config';\nimport { toError } from '../../toError';\n\nexport interface ValidateNoSkipLevelDepsOptions {\n // No options needed\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface RedundantDep {\n project: string;\n redundantDep: string;\n alreadyBroughtInBy: string;\n}\n\n/**\n * Compute all transitive dependencies for a project\n */\nfunction computeTransitiveDeps(\n project: string,\n graph: Record<string, string[]>,\n visited: Set<string> = new Set()\n): Set<string> {\n const result = new Set<string>();\n\n if (visited.has(project)) {\n return result;\n }\n visited.add(project);\n\n const directDeps = graph[project] || [];\n for (const dep of directDeps) {\n result.add(dep);\n // Recursively get transitive deps\n const transitive = computeTransitiveDeps(dep, graph, visited);\n for (const t of transitive) {\n result.add(t);\n }\n }\n\n return result;\n}\n\n/**\n * Find redundant dependencies for a project\n */\nfunction findRedundantDeps(\n project: string,\n graph: Record<string, string[]>\n): RedundantDep[] {\n const redundant: RedundantDep[] = [];\n const directDeps = graph[project] || [];\n\n // For each direct dependency, compute what it transitively brings in\n const transitiveByDep = new Map<string, Set<string>>();\n for (const dep of directDeps) {\n transitiveByDep.set(dep, computeTransitiveDeps(dep, graph));\n }\n\n // Check if any direct dependency is already brought in by another\n const transitiveEntries = Array.from(transitiveByDep.entries());\n for (const dep of directDeps) {\n for (const entry of transitiveEntries) {\n const otherDep = entry[0];\n const otherTransitive = entry[1];\n if (otherDep !== dep && otherTransitive.has(dep)) {\n redundant.push({\n project,\n redundantDep: dep,\n alreadyBroughtInBy: otherDep,\n });\n break; // Only report once per redundant dep\n }\n }\n }\n\n return redundant;\n}\n\n/**\n * Write documentation file when violations are found\n */\nfunction writeDocFile(workspaceRoot: string): void {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n writeTemplate(workspaceRoot, 'webpieces.transitivedeps.md');\n } catch (err: unknown) {\n const error = toError(err);\n console.warn('Could not write webpieces.transitivedeps.md:', error.message);\n }\n}\n\nexport default async function runExecutor(\n _options: ValidateNoSkipLevelDepsOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n console.log('\\nšŸ”„ Validating No Skip-Level Dependencies\\n');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Step 1: Generate current graph from project.json files\n console.log('šŸ“Š Generating dependency graph from project.json files...');\n const graph = await generateGraph();\n\n // Step 2: Find all redundant dependencies\n console.log('šŸ” Checking for redundant transitive dependencies...');\n const allRedundant: RedundantDep[] = [];\n\n for (const project of Object.keys(graph)) {\n const redundant = findRedundantDeps(project, graph);\n allRedundant.push(...redundant);\n }\n\n if (allRedundant.length === 0) {\n console.log('āœ… No redundant transitive dependencies detected!');\n console.log('\\nšŸ“ˆ Graph is clean and minimal.');\n return { success: true };\n }\n\n // Write documentation file\n const workspaceRoot = context.root || process.cwd();\n writeDocFile(workspaceRoot);\n\n // Report violations\n console.error('\\nāŒ Redundant transitive dependencies detected!\\n');\n console.error('āš ļø AI Agent: READ .webpieces/instruct-ai/webpieces.transitivedeps.md for fix instructions!\\n');\n\n for (const r of allRedundant) {\n console.error(` ${r.project}:`);\n console.error(` └─ \"${r.redundantDep}\" is REDUNDANT`);\n console.error(` (already brought in by \"${r.alreadyBroughtInBy}\")\\n`);\n }\n\n console.error('\\nTo fix:');\n console.error(' 1. READ .webpieces/instruct-ai/webpieces.transitivedeps.md');\n console.error(' 2. Remove redundant deps from project.json build.dependsOn');\n console.error(' 3. Remove redundant deps from package.json dependencies');\n console.error(' 4. Run: npx nx run architecture:generate');\n console.error(' 5. Run: npm run build-all');\n\n return { success: false };\n } catch (err: unknown) {\n const error = toError(err);\n console.error('āŒ Skip-level validation failed:', error.message);\n return { success: false };\n }\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-no-skiplevel-deps/executor.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;AAYH,8BAUC;AAVc,KAAK,UAAU,WAAW,CACrC,QAAwC,EACxC,QAAyB;IAEzB,OAAO,CAAC,GAAG,CACP,wDAAwD;QACpD,sFAAsF;QACtF,8DAA8D,CACrE,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC7B,CAAC","sourcesContent":["/**\n * Validate No Skip-Level Dependencies Executor — RETIRED (no-op).\n *\n * Skip-level (redundant transitive) edges used to be an error here. That is no longer\n * meaningful: `architecture:generate` now derives the graph from nx's project graph and\n * applies transitive reduction, so the committed architecture/dependencies.json can never\n * contain a redundant edge. The check is superseded by auto-reduction.\n *\n * Worse, its old remediation told users to remove \"redundant\" deps from package.json —\n * which is exactly the runtime-validity trap (a transitively-reachable package.json entry\n * can still be a real runtime dependency, e.g. a peerDependency or generated client).\n *\n * Defaults off (workspace.validations.noSkipLevelDeps=false). Kept as a no-op for one\n * release so any explicit enablement does not error on now-expected skip-level edges.\n *\n * Usage:\n * nx run architecture:validate-no-skiplevel-deps\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\n\nexport interface ValidateNoSkipLevelDepsOptions {\n // No options needed\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nexport default async function runExecutor(\n _options: ValidateNoSkipLevelDepsOptions,\n _context: ExecutorContext\n): Promise<ExecutorResult> {\n console.log(\n '\\nā­ļø validate-no-skiplevel-deps is retired (no-op).\\n' +\n ' Superseded by auto-reduction in `architecture:generate`: the committed graph is\\n' +\n ' transitively reduced, so skip-level edges cannot occur.\\n'\n );\n return { success: true };\n}\n"]}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Validate Nx Wiring Executor
3
+ *
4
+ * Enforces that the webpieces validators are actually wired into the build. Two checks:
5
+ *
6
+ * 1. nx.json targetDefaults — the compile executors (@nx/js:tsc, @angular/build:application)
7
+ * must carry the load-bearing dependsOn:
8
+ * ["architecture:validate-complete", "validate-no-file-import-cycles", "^build"]
9
+ *
10
+ * 2. Per-project override guard — a project that declares its OWN build.dependsOn OVERRIDES
11
+ * the targetDefaults entirely (nx does not merge dependsOn). That silently drops `^build`
12
+ * (→ upstream libs not built first, builds against an empty dist) AND the validator gates
13
+ * (→ the project builds green while validating nothing). So we check each compile project's
14
+ * RESOLVED build.dependsOn and fail if it is missing any required entry.
15
+ *
16
+ * If either is stripped, validators exist but never run and the build stays green while
17
+ * validating nothing. This executor fails when the wiring is missing.
18
+ *
19
+ * Conservative by design: only REQUIRES wiring on compile executors actually in use
20
+ * (@nx/js:tsc, @angular/build:application). A repo that uses neither passes.
21
+ *
22
+ * Disable via webpieces.config.json rules["nx-wiring"].mode="OFF".
23
+ *
24
+ * Usage: nx run architecture:validate-nx-wiring
25
+ */
26
+ import type { ExecutorContext } from '@nx/devkit';
27
+ export interface ValidateNxWiringOptions {
28
+ requiredDeps?: string[];
29
+ compileExecutors?: string[];
30
+ }
31
+ export interface ExecutorResult {
32
+ success: boolean;
33
+ }
34
+ export default function runExecutor(options: ValidateNxWiringOptions, context: ExecutorContext): Promise<ExecutorResult>;
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ /**
3
+ * Validate Nx Wiring Executor
4
+ *
5
+ * Enforces that the webpieces validators are actually wired into the build. Two checks:
6
+ *
7
+ * 1. nx.json targetDefaults — the compile executors (@nx/js:tsc, @angular/build:application)
8
+ * must carry the load-bearing dependsOn:
9
+ * ["architecture:validate-complete", "validate-no-file-import-cycles", "^build"]
10
+ *
11
+ * 2. Per-project override guard — a project that declares its OWN build.dependsOn OVERRIDES
12
+ * the targetDefaults entirely (nx does not merge dependsOn). That silently drops `^build`
13
+ * (→ upstream libs not built first, builds against an empty dist) AND the validator gates
14
+ * (→ the project builds green while validating nothing). So we check each compile project's
15
+ * RESOLVED build.dependsOn and fail if it is missing any required entry.
16
+ *
17
+ * If either is stripped, validators exist but never run and the build stays green while
18
+ * validating nothing. This executor fails when the wiring is missing.
19
+ *
20
+ * Conservative by design: only REQUIRES wiring on compile executors actually in use
21
+ * (@nx/js:tsc, @angular/build:application). A repo that uses neither passes.
22
+ *
23
+ * Disable via webpieces.config.json rules["nx-wiring"].mode="OFF".
24
+ *
25
+ * Usage: nx run architecture:validate-nx-wiring
26
+ */
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.default = runExecutor;
29
+ const tslib_1 = require("tslib");
30
+ const devkit_1 = require("@nx/devkit");
31
+ const rules_config_1 = require("@webpieces/rules-config");
32
+ const fs = tslib_1.__importStar(require("fs"));
33
+ const path = tslib_1.__importStar(require("path"));
34
+ const DEFAULT_REQUIRED_DEPS = [
35
+ 'architecture:validate-complete',
36
+ 'validate-no-file-import-cycles',
37
+ ];
38
+ // Per-project build targets must ALSO keep `^build` so build order follows nx's full graph.
39
+ const BUILD_ORDER_DEP = '^build';
40
+ const DEFAULT_COMPILE_EXECUTORS = [
41
+ '@nx/js:tsc',
42
+ '@angular/build:application',
43
+ ];
44
+ class WiringProblem {
45
+ constructor(executorName, missing, found) {
46
+ this.executorName = executorName;
47
+ this.missing = missing;
48
+ this.found = found;
49
+ }
50
+ }
51
+ class ProjectGateProblem {
52
+ constructor(project, executorName, missing, found) {
53
+ this.project = project;
54
+ this.executorName = executorName;
55
+ this.missing = missing;
56
+ this.found = found;
57
+ }
58
+ }
59
+ function readTargetDefaults(workspaceRoot) {
60
+ const nxJsonPath = path.join(workspaceRoot, 'nx.json');
61
+ if (!fs.existsSync(nxJsonPath))
62
+ return {};
63
+ // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
64
+ try {
65
+ const raw = fs.readFileSync(nxJsonPath, 'utf8');
66
+ const parsed = JSON.parse(raw);
67
+ return parsed.targetDefaults ?? {};
68
+ // webpieces-disable catch-error-pattern -- malformed nx.json fails open so the check does not crash the build
69
+ }
70
+ catch (err) {
71
+ //const error = toError(err); -- malformed nx.json fails open
72
+ void err;
73
+ return {};
74
+ }
75
+ }
76
+ function findCompileExecutorsInUse(projectsConfig, compileExecutors) {
77
+ const known = new Set(compileExecutors);
78
+ const inUse = new Set();
79
+ for (const cfg of Object.values(projectsConfig.projects)) {
80
+ const targets = cfg.targets ?? {};
81
+ for (const target of Object.values(targets)) {
82
+ const executorName = target.executor;
83
+ if (executorName && known.has(executorName)) {
84
+ inUse.add(executorName);
85
+ }
86
+ }
87
+ }
88
+ return inUse;
89
+ }
90
+ function findProblems(relevantExecutors, targetDefaults, requiredDeps) {
91
+ const problems = [];
92
+ for (const executorName of relevantExecutors) {
93
+ const entry = targetDefaults[executorName];
94
+ const dependsOn = entry?.dependsOn ?? [];
95
+ const missing = requiredDeps.filter((dep) => !dependsOn.includes(dep));
96
+ if (missing.length > 0) {
97
+ problems.push(new WiringProblem(executorName, missing, dependsOn));
98
+ }
99
+ }
100
+ return problems;
101
+ }
102
+ /**
103
+ * Normalize an nx dependsOn entry to a comparable string. The string form ("^build",
104
+ * "validate-complete") passes through; the object form is rendered the same way
105
+ * ({target:"build", dependencies:true} → "^build", {target:"build"} → "build").
106
+ */
107
+ function normalizeDeps(deps) {
108
+ return deps.map((dep) => {
109
+ if (typeof dep === 'string')
110
+ return dep;
111
+ const target = dep.target ?? '';
112
+ return dep.dependencies ? `^${target}` : target;
113
+ });
114
+ }
115
+ /**
116
+ * Check each compile project's RESOLVED build.dependsOn (targetDefaults already merged in)
117
+ * for the required gates + `^build`. A project that overrode them away is flagged.
118
+ */
119
+ function findProjectGateProblems(projectsConfig, compileExecutors, requiredPerProject) {
120
+ const problems = [];
121
+ for (const [name, cfg] of Object.entries(projectsConfig.projects)) {
122
+ // Tooling/foundation packages (type:tooling) BUILD the validators, so gating their own
123
+ // build on validate-complete would create a bootstrap cycle. They are exempt: they keep
124
+ // build-order ("^build") only. Application/library code is still fully gated.
125
+ if ((cfg.tags ?? []).includes('type:tooling'))
126
+ continue;
127
+ const build = cfg.targets?.['build'];
128
+ if (!build || !build.executor || !compileExecutors.has(build.executor))
129
+ continue;
130
+ const dependsOn = normalizeDeps(build.dependsOn ?? []);
131
+ const missing = requiredPerProject.filter((dep) => !dependsOn.includes(dep));
132
+ if (missing.length > 0) {
133
+ problems.push(new ProjectGateProblem(name, build.executor, missing, dependsOn));
134
+ }
135
+ }
136
+ return problems;
137
+ }
138
+ function reportFailure(problems, requiredDeps) {
139
+ console.error('\nāŒ webpieces validators are not wired into your build (nx.json).\n');
140
+ console.error('The validators exist but no build depends on them, so they never run.');
141
+ console.error('Add the missing dependsOn entries to nx.json targetDefaults:\n');
142
+ const depsList = requiredDeps.map((dep) => `"${dep}"`).join(', ');
143
+ for (const problem of problems) {
144
+ const missingList = problem.missing.map((dep) => `"${dep}"`).join(', ');
145
+ console.error(` "${problem.executorName}": {`);
146
+ console.error(` "dependsOn": [${depsList}, "^build"]`);
147
+ console.error(' }');
148
+ console.error(` missing: ${missingList}\n`);
149
+ }
150
+ console.error('To turn this wiring check off, set rules["nx-wiring"].mode="OFF" in');
151
+ console.error('webpieces.config.json.\n');
152
+ }
153
+ function reportProjectGateFailure(problems) {
154
+ console.error('\nāŒ Some projects override away the build gates in their project.json.\n');
155
+ console.error('A project-level build.dependsOn OVERRIDES nx.json targetDefaults (nx does not');
156
+ console.error('merge dependsOn). That silently drops "^build" (upstreams not built first →');
157
+ console.error('builds against an empty dist) and/or the validators (build stays green while');
158
+ console.error('validating nothing).\n');
159
+ console.error('Fix: remove build.dependsOn from these project.json files so targetDefaults');
160
+ console.error('apply, OR include all required entries explicitly:\n');
161
+ for (const p of problems) {
162
+ const missingList = p.missing.map((dep) => `"${dep}"`).join(', ');
163
+ console.error(` ${p.project} (${p.executorName}):`);
164
+ console.error(` resolved build.dependsOn: ${JSON.stringify(p.found)}`);
165
+ console.error(` missing: ${missingList}\n`);
166
+ }
167
+ }
168
+ async function runExecutor(options, context) {
169
+ const shared = (0, rules_config_1.loadConfig)(context.root);
170
+ const rule = shared.rules.get('nx-wiring');
171
+ if (rule && rule.isOff) {
172
+ console.log('\nā­ļø Skipping validate-nx-wiring (mode: OFF)\n');
173
+ return { success: true };
174
+ }
175
+ const requiredDeps = options.requiredDeps ?? DEFAULT_REQUIRED_DEPS;
176
+ const compileExecutors = options.compileExecutors ?? DEFAULT_COMPILE_EXECUTORS;
177
+ console.log('\nšŸ”Œ Validating webpieces validators are wired into the build\n');
178
+ const projectGraph = await (0, devkit_1.createProjectGraphAsync)();
179
+ const projectsConfig = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
180
+ const inUse = findCompileExecutorsInUse(projectsConfig, compileExecutors);
181
+ const relevantExecutors = compileExecutors.filter((executorName) => inUse.has(executorName));
182
+ if (relevantExecutors.length === 0) {
183
+ console.log('āœ… No known compile executors in use — nothing to gate\n');
184
+ return { success: true };
185
+ }
186
+ const targetDefaults = readTargetDefaults(context.root);
187
+ const wiringProblems = findProblems(relevantExecutors, targetDefaults, requiredDeps);
188
+ const gateProblems = findProjectGateProblems(projectsConfig, inUse, [
189
+ ...requiredDeps,
190
+ BUILD_ORDER_DEP,
191
+ ]);
192
+ if (wiringProblems.length === 0 && gateProblems.length === 0) {
193
+ console.log('āœ… Validators are wired into the build (targetDefaults + every project)\n');
194
+ return { success: true };
195
+ }
196
+ if (wiringProblems.length > 0)
197
+ reportFailure(wiringProblems, requiredDeps);
198
+ if (gateProblems.length > 0)
199
+ reportProjectGateFailure(gateProblems);
200
+ return { success: false };
201
+ }
202
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-nx-wiring/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Nx Wiring Executor\n *\n * Enforces that the webpieces validators are actually wired into the build. Two checks:\n *\n * 1. nx.json targetDefaults — the compile executors (@nx/js:tsc, @angular/build:application)\n * must carry the load-bearing dependsOn:\n * [\"architecture:validate-complete\", \"validate-no-file-import-cycles\", \"^build\"]\n *\n * 2. Per-project override guard — a project that declares its OWN build.dependsOn OVERRIDES\n * the targetDefaults entirely (nx does not merge dependsOn). That silently drops `^build`\n * (→ upstream libs not built first, builds against an empty dist) AND the validator gates\n * (→ the project builds green while validating nothing). So we check each compile project's\n * RESOLVED build.dependsOn and fail if it is missing any required entry.\n *\n * If either is stripped, validators exist but never run and the build stays green while\n * validating nothing. This executor fails when the wiring is missing.\n *\n * Conservative by design: only REQUIRES wiring on compile executors actually in use\n * (@nx/js:tsc, @angular/build:application). A repo that uses neither passes.\n *\n * Disable via webpieces.config.json rules[\"nx-wiring\"].mode=\"OFF\".\n *\n * Usage: nx run architecture:validate-nx-wiring\n */\n\nimport type {\n ExecutorContext,\n ProjectsConfigurations,\n TargetDependencyConfig,\n} from '@nx/devkit';\nimport { createProjectGraphAsync, readProjectsConfigurationFromProjectGraph } from '@nx/devkit';\nimport { loadConfig } from '@webpieces/rules-config';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nexport interface ValidateNxWiringOptions {\n requiredDeps?: string[];\n compileExecutors?: string[];\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nconst DEFAULT_REQUIRED_DEPS: string[] = [\n 'architecture:validate-complete',\n 'validate-no-file-import-cycles',\n];\n\n// Per-project build targets must ALSO keep `^build` so build order follows nx's full graph.\nconst BUILD_ORDER_DEP = '^build';\n\nconst DEFAULT_COMPILE_EXECUTORS: string[] = [\n '@nx/js:tsc',\n '@angular/build:application',\n];\n\nclass WiringProblem {\n executorName: string;\n missing: string[];\n found: string[];\n\n constructor(executorName: string, missing: string[], found: string[]) {\n this.executorName = executorName;\n this.missing = missing;\n this.found = found;\n }\n}\n\nclass ProjectGateProblem {\n project: string;\n executorName: string;\n missing: string[];\n found: string[];\n\n constructor(project: string, executorName: string, missing: string[], found: string[]) {\n this.project = project;\n this.executorName = executorName;\n this.missing = missing;\n this.found = found;\n }\n}\n\ninterface TargetDefaultEntry {\n dependsOn?: string[];\n}\n\ninterface RawNxJson {\n targetDefaults?: Record<string, TargetDefaultEntry>;\n}\n\nfunction readTargetDefaults(workspaceRoot: string): Record<string, TargetDefaultEntry> {\n const nxJsonPath = path.join(workspaceRoot, 'nx.json');\n if (!fs.existsSync(nxJsonPath)) return {};\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const raw = fs.readFileSync(nxJsonPath, 'utf8');\n const parsed = JSON.parse(raw) as RawNxJson;\n return parsed.targetDefaults ?? {};\n // webpieces-disable catch-error-pattern -- malformed nx.json fails open so the check does not crash the build\n } catch (err: unknown) {\n //const error = toError(err); -- malformed nx.json fails open\n void err;\n return {};\n }\n}\n\nfunction findCompileExecutorsInUse(\n projectsConfig: ProjectsConfigurations,\n compileExecutors: string[],\n): Set<string> {\n const known = new Set(compileExecutors);\n const inUse = new Set<string>();\n for (const cfg of Object.values(projectsConfig.projects)) {\n const targets = cfg.targets ?? {};\n for (const target of Object.values(targets)) {\n const executorName = target.executor;\n if (executorName && known.has(executorName)) {\n inUse.add(executorName);\n }\n }\n }\n return inUse;\n}\n\nfunction findProblems(\n relevantExecutors: string[],\n targetDefaults: Record<string, TargetDefaultEntry>,\n requiredDeps: string[],\n): WiringProblem[] {\n const problems: WiringProblem[] = [];\n for (const executorName of relevantExecutors) {\n const entry = targetDefaults[executorName];\n const dependsOn = entry?.dependsOn ?? [];\n const missing = requiredDeps.filter((dep: string) => !dependsOn.includes(dep));\n if (missing.length > 0) {\n problems.push(new WiringProblem(executorName, missing, dependsOn));\n }\n }\n return problems;\n}\n\n/**\n * Normalize an nx dependsOn entry to a comparable string. The string form (\"^build\",\n * \"validate-complete\") passes through; the object form is rendered the same way\n * ({target:\"build\", dependencies:true} → \"^build\", {target:\"build\"} → \"build\").\n */\nfunction normalizeDeps(deps: (string | TargetDependencyConfig)[]): string[] {\n return deps.map((dep) => {\n if (typeof dep === 'string') return dep;\n const target = dep.target ?? '';\n return dep.dependencies ? `^${target}` : target;\n });\n}\n\n/**\n * Check each compile project's RESOLVED build.dependsOn (targetDefaults already merged in)\n * for the required gates + `^build`. A project that overrode them away is flagged.\n */\nfunction findProjectGateProblems(\n projectsConfig: ProjectsConfigurations,\n compileExecutors: Set<string>,\n requiredPerProject: string[],\n): ProjectGateProblem[] {\n const problems: ProjectGateProblem[] = [];\n for (const [name, cfg] of Object.entries(projectsConfig.projects)) {\n // Tooling/foundation packages (type:tooling) BUILD the validators, so gating their own\n // build on validate-complete would create a bootstrap cycle. They are exempt: they keep\n // build-order (\"^build\") only. Application/library code is still fully gated.\n if ((cfg.tags ?? []).includes('type:tooling')) continue;\n const build = cfg.targets?.['build'];\n if (!build || !build.executor || !compileExecutors.has(build.executor)) continue;\n const dependsOn = normalizeDeps(build.dependsOn ?? []);\n const missing = requiredPerProject.filter((dep) => !dependsOn.includes(dep));\n if (missing.length > 0) {\n problems.push(new ProjectGateProblem(name, build.executor, missing, dependsOn));\n }\n }\n return problems;\n}\n\nfunction reportFailure(problems: WiringProblem[], requiredDeps: string[]): void {\n console.error('\\nāŒ webpieces validators are not wired into your build (nx.json).\\n');\n console.error('The validators exist but no build depends on them, so they never run.');\n console.error('Add the missing dependsOn entries to nx.json targetDefaults:\\n');\n const depsList = requiredDeps.map((dep: string) => `\"${dep}\"`).join(', ');\n for (const problem of problems) {\n const missingList = problem.missing.map((dep: string) => `\"${dep}\"`).join(', ');\n console.error(` \"${problem.executorName}\": {`);\n console.error(` \"dependsOn\": [${depsList}, \"^build\"]`);\n console.error(' }');\n console.error(` missing: ${missingList}\\n`);\n }\n console.error('To turn this wiring check off, set rules[\"nx-wiring\"].mode=\"OFF\" in');\n console.error('webpieces.config.json.\\n');\n}\n\nfunction reportProjectGateFailure(problems: ProjectGateProblem[]): void {\n console.error('\\nāŒ Some projects override away the build gates in their project.json.\\n');\n console.error('A project-level build.dependsOn OVERRIDES nx.json targetDefaults (nx does not');\n console.error('merge dependsOn). That silently drops \"^build\" (upstreams not built first →');\n console.error('builds against an empty dist) and/or the validators (build stays green while');\n console.error('validating nothing).\\n');\n console.error('Fix: remove build.dependsOn from these project.json files so targetDefaults');\n console.error('apply, OR include all required entries explicitly:\\n');\n for (const p of problems) {\n const missingList = p.missing.map((dep) => `\"${dep}\"`).join(', ');\n console.error(` ${p.project} (${p.executorName}):`);\n console.error(` resolved build.dependsOn: ${JSON.stringify(p.found)}`);\n console.error(` missing: ${missingList}\\n`);\n }\n}\n\nexport default async function runExecutor(\n options: ValidateNxWiringOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n const shared = loadConfig(context.root);\n const rule = shared.rules.get('nx-wiring');\n if (rule && rule.isOff) {\n console.log('\\nā­ļø Skipping validate-nx-wiring (mode: OFF)\\n');\n return { success: true };\n }\n\n const requiredDeps = options.requiredDeps ?? DEFAULT_REQUIRED_DEPS;\n const compileExecutors = options.compileExecutors ?? DEFAULT_COMPILE_EXECUTORS;\n\n console.log('\\nšŸ”Œ Validating webpieces validators are wired into the build\\n');\n\n const projectGraph = await createProjectGraphAsync();\n const projectsConfig = readProjectsConfigurationFromProjectGraph(projectGraph);\n\n const inUse = findCompileExecutorsInUse(projectsConfig, compileExecutors);\n const relevantExecutors = compileExecutors.filter((executorName: string) =>\n inUse.has(executorName),\n );\n\n if (relevantExecutors.length === 0) {\n console.log('āœ… No known compile executors in use — nothing to gate\\n');\n return { success: true };\n }\n\n const targetDefaults = readTargetDefaults(context.root);\n const wiringProblems = findProblems(relevantExecutors, targetDefaults, requiredDeps);\n const gateProblems = findProjectGateProblems(projectsConfig, inUse, [\n ...requiredDeps,\n BUILD_ORDER_DEP,\n ]);\n\n if (wiringProblems.length === 0 && gateProblems.length === 0) {\n console.log('āœ… Validators are wired into the build (targetDefaults + every project)\\n');\n return { success: true };\n }\n\n if (wiringProblems.length > 0) reportFailure(wiringProblems, requiredDeps);\n if (gateProblems.length > 0) reportProjectGateFailure(gateProblems);\n return { success: false };\n}\n"]}