@webpieces/nx-webpieces-rules 0.3.129 → 0.3.131

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/nx-webpieces-rules",
3
- "version": "0.3.129",
3
+ "version": "0.3.131",
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.129",
22
- "@webpieces/code-rules": "0.3.129",
23
- "@webpieces/eslint-rules": "0.3.129",
24
- "@webpieces/rules-config": "0.3.129"
21
+ "@webpieces/ai-hook-rules": "0.3.131",
22
+ "@webpieces/code-rules": "0.3.131",
23
+ "@webpieces/eslint-rules": "0.3.131",
24
+ "@webpieces/rules-config": "0.3.131"
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"]}
@@ -1,24 +1,25 @@
1
1
  /**
2
2
  * Validate Nx Wiring Executor
3
3
  *
4
- * Enforces that the webpieces validators are actually wired into the build in
5
- * nx.json. The plugin auto-infers the validator targets (architecture:validate-complete,
6
- * per-project validate-no-file-import-cycles), but the load-bearing connection that
7
- * makes a build DEPEND on them lives in each repo's hand-edited nx.json:
4
+ * Enforces that the webpieces validators are actually wired into the build. Two checks:
8
5
  *
9
- * "@nx/js:tsc": {
10
- * "dependsOn": ["architecture:validate-complete", "validate-no-file-import-cycles", "^build"]
11
- * }
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"]
12
9
  *
13
- * If that dependsOn is stripped, the validators exist but never run and a build stays
14
- * green while validating nothing. This executor fails when the wiring is missing.
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
15
  *
16
- * Conservative by design: it only REQUIRES wiring on compile executors that are
17
- * actually used somewhere in the project graph (@nx/js:tsc, @angular/build:application).
18
- * A repo that uses neither has nothing to gate and passes.
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.
19
18
  *
20
- * Disable per validator in webpieces.config.json (rules[name].mode="OFF"), but the
21
- * wiring itself is governed by the "nx-wiring" rule (default on) so the build gate stays.
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".
22
23
  *
23
24
  * Usage: nx run architecture:validate-nx-wiring
24
25
  */
@@ -2,24 +2,25 @@
2
2
  /**
3
3
  * Validate Nx Wiring Executor
4
4
  *
5
- * Enforces that the webpieces validators are actually wired into the build in
6
- * nx.json. The plugin auto-infers the validator targets (architecture:validate-complete,
7
- * per-project validate-no-file-import-cycles), but the load-bearing connection that
8
- * makes a build DEPEND on them lives in each repo's hand-edited nx.json:
5
+ * Enforces that the webpieces validators are actually wired into the build. Two checks:
9
6
  *
10
- * "@nx/js:tsc": {
11
- * "dependsOn": ["architecture:validate-complete", "validate-no-file-import-cycles", "^build"]
12
- * }
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"]
13
10
  *
14
- * If that dependsOn is stripped, the validators exist but never run and a build stays
15
- * green while validating nothing. This executor fails when the wiring is missing.
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
16
  *
17
- * Conservative by design: it only REQUIRES wiring on compile executors that are
18
- * actually used somewhere in the project graph (@nx/js:tsc, @angular/build:application).
19
- * A repo that uses neither has nothing to gate and passes.
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.
20
19
  *
21
- * Disable per validator in webpieces.config.json (rules[name].mode="OFF"), but the
22
- * wiring itself is governed by the "nx-wiring" rule (default on) so the build gate stays.
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".
23
24
  *
24
25
  * Usage: nx run architecture:validate-nx-wiring
25
26
  */
@@ -34,6 +35,8 @@ const DEFAULT_REQUIRED_DEPS = [
34
35
  'architecture:validate-complete',
35
36
  'validate-no-file-import-cycles',
36
37
  ];
38
+ // Per-project build targets must ALSO keep `^build` so build order follows nx's full graph.
39
+ const BUILD_ORDER_DEP = '^build';
37
40
  const DEFAULT_COMPILE_EXECUTORS = [
38
41
  '@nx/js:tsc',
39
42
  '@angular/build:application',
@@ -45,6 +48,14 @@ class WiringProblem {
45
48
  this.found = found;
46
49
  }
47
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
+ }
48
59
  function readTargetDefaults(workspaceRoot) {
49
60
  const nxJsonPath = path.join(workspaceRoot, 'nx.json');
50
61
  if (!fs.existsSync(nxJsonPath))
@@ -62,9 +73,7 @@ function readTargetDefaults(workspaceRoot) {
62
73
  return {};
63
74
  }
64
75
  }
65
- async function findCompileExecutorsInUse(compileExecutors) {
66
- const projectGraph = await (0, devkit_1.createProjectGraphAsync)();
67
- const projectsConfig = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
76
+ function findCompileExecutorsInUse(projectsConfig, compileExecutors) {
68
77
  const known = new Set(compileExecutors);
69
78
  const inUse = new Set();
70
79
  for (const cfg of Object.values(projectsConfig.projects)) {
@@ -90,8 +99,44 @@ function findProblems(relevantExecutors, targetDefaults, requiredDeps) {
90
99
  }
91
100
  return problems;
92
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
+ }
93
138
  function reportFailure(problems, requiredDeps) {
94
- console.error('\nāŒ webpieces validators are not wired into your build.\n');
139
+ console.error('\nāŒ webpieces validators are not wired into your build (nx.json).\n');
95
140
  console.error('The validators exist but no build depends on them, so they never run.');
96
141
  console.error('Add the missing dependsOn entries to nx.json targetDefaults:\n');
97
142
  const depsList = requiredDeps.map((dep) => `"${dep}"`).join(', ');
@@ -102,10 +147,23 @@ function reportFailure(problems, requiredDeps) {
102
147
  console.error(' }');
103
148
  console.error(` missing: ${missingList}\n`);
104
149
  }
105
- console.error('To disable an INDIVIDUAL validator, set rules[name].mode="OFF" in');
106
- console.error('webpieces.config.json — but the wiring above must stay installed so the');
107
- console.error('build gate keeps working. To turn this wiring check itself off, set');
108
- console.error('rules["nx-wiring"].mode="OFF" in webpieces.config.json.\n');
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
+ }
109
167
  }
110
168
  async function runExecutor(options, context) {
111
169
  const shared = (0, rules_config_1.loadConfig)(context.root);
@@ -117,19 +175,28 @@ async function runExecutor(options, context) {
117
175
  const requiredDeps = options.requiredDeps ?? DEFAULT_REQUIRED_DEPS;
118
176
  const compileExecutors = options.compileExecutors ?? DEFAULT_COMPILE_EXECUTORS;
119
177
  console.log('\nšŸ”Œ Validating webpieces validators are wired into the build\n');
120
- const inUse = await findCompileExecutorsInUse(compileExecutors);
178
+ const projectGraph = await (0, devkit_1.createProjectGraphAsync)();
179
+ const projectsConfig = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
180
+ const inUse = findCompileExecutorsInUse(projectsConfig, compileExecutors);
121
181
  const relevantExecutors = compileExecutors.filter((executorName) => inUse.has(executorName));
122
182
  if (relevantExecutors.length === 0) {
123
183
  console.log('āœ… No known compile executors in use — nothing to gate\n');
124
184
  return { success: true };
125
185
  }
126
186
  const targetDefaults = readTargetDefaults(context.root);
127
- const problems = findProblems(relevantExecutors, targetDefaults, requiredDeps);
128
- if (problems.length === 0) {
129
- console.log('āœ… Validators are wired into the build\n');
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');
130
194
  return { success: true };
131
195
  }
132
- reportFailure(problems, requiredDeps);
196
+ if (wiringProblems.length > 0)
197
+ reportFailure(wiringProblems, requiredDeps);
198
+ if (gateProblems.length > 0)
199
+ reportProjectGateFailure(gateProblems);
133
200
  return { success: false };
134
201
  }
135
202
  //# sourceMappingURL=executor.js.map