@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 +5 -0
- package/package.json +5 -5
- package/src/executors/generate/executor.js +4 -4
- package/src/executors/generate/executor.js.map +1 -1
- package/src/executors/validate-architecture-unchanged/executor.js +3 -3
- package/src/executors/validate-architecture-unchanged/executor.js.map +1 -1
- package/src/executors/validate-no-skiplevel-deps/executor.d.ts +12 -6
- package/src/executors/validate-no-skiplevel-deps/executor.js +16 -113
- package/src/executors/validate-no-skiplevel-deps/executor.js.map +1 -1
- package/src/executors/validate-nx-wiring/executor.d.ts +34 -0
- package/src/executors/validate-nx-wiring/executor.js +202 -0
- package/src/executors/validate-nx-wiring/executor.js.map +1 -0
- package/src/executors/validate-nx-wiring/schema.json +19 -0
- package/src/executors/validate-packagejson/executor.js +14 -8
- package/src/executors/validate-packagejson/executor.js.map +1 -1
- package/src/lib/graph-generator.d.ts +27 -8
- package/src/lib/graph-generator.js +48 -53
- package/src/lib/graph-generator.js.map +1 -1
- package/src/lib/package-validator.d.ts +10 -0
- package/src/lib/package-validator.js +12 -5
- package/src/lib/package-validator.js.map +1 -1
- package/src/lib/transitive-reduction.d.ts +25 -0
- package/src/lib/transitive-reduction.js +56 -0
- package/src/lib/transitive-reduction.js.map +1 -0
- package/src/plugin.d.ts +1 -0
- package/src/plugin.js +21 -1
- package/src/plugin.js.map +1 -1
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.
|
|
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.
|
|
22
|
-
"@webpieces/code-rules": "0.3.
|
|
23
|
-
"@webpieces/eslint-rules": "0.3.
|
|
24
|
-
"@webpieces/rules-config": "0.3.
|
|
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:
|
|
23
|
-
console.log(
|
|
24
|
-
const
|
|
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)(
|
|
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,+
|
|
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:
|
|
45
|
+
// Step 1: Build the full graph from nx, then transitively reduce it
|
|
46
46
|
console.log('š Generating current dependency graph...');
|
|
47
|
-
const
|
|
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)(
|
|
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":";AAAA;;;;;;;;GAQG;;AA8BH,8BAoEC;AA/FD,0DAAwD;AACxD,+
|
|
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
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
-
*
|
|
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,
|
|
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
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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":";AAAA
|
|
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"]}
|