@webpieces/dev-config 0.2.17 → 0.2.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/architecture/executors/generate/executor.d.ts +17 -0
  2. package/architecture/executors/generate/executor.js +67 -0
  3. package/architecture/executors/generate/executor.js.map +1 -0
  4. package/architecture/executors/generate/executor.ts +83 -0
  5. package/architecture/executors/generate/schema.json +14 -0
  6. package/architecture/executors/validate-architecture-unchanged/executor.d.ts +17 -0
  7. package/architecture/executors/validate-architecture-unchanged/executor.js +65 -0
  8. package/architecture/executors/validate-architecture-unchanged/executor.js.map +1 -0
  9. package/architecture/executors/validate-architecture-unchanged/executor.ts +81 -0
  10. package/architecture/executors/validate-architecture-unchanged/schema.json +14 -0
  11. package/architecture/executors/validate-no-cycles/executor.d.ts +16 -0
  12. package/architecture/executors/validate-no-cycles/executor.js +48 -0
  13. package/architecture/executors/validate-no-cycles/executor.js.map +1 -0
  14. package/architecture/executors/validate-no-cycles/executor.ts +60 -0
  15. package/architecture/executors/validate-no-cycles/schema.json +8 -0
  16. package/architecture/executors/validate-no-skiplevel-deps/executor.d.ts +19 -0
  17. package/architecture/executors/validate-no-skiplevel-deps/executor.js +227 -0
  18. package/architecture/executors/validate-no-skiplevel-deps/executor.js.map +1 -0
  19. package/architecture/executors/validate-no-skiplevel-deps/executor.ts +267 -0
  20. package/architecture/executors/validate-no-skiplevel-deps/schema.json +8 -0
  21. package/architecture/executors/visualize/executor.d.ts +17 -0
  22. package/architecture/executors/visualize/executor.js +49 -0
  23. package/architecture/executors/visualize/executor.js.map +1 -0
  24. package/architecture/executors/visualize/executor.ts +63 -0
  25. package/architecture/executors/visualize/schema.json +14 -0
  26. package/architecture/index.d.ts +19 -0
  27. package/architecture/index.js +23 -0
  28. package/architecture/index.js.map +1 -0
  29. package/architecture/index.ts +20 -0
  30. package/architecture/lib/graph-comparator.d.ts +39 -0
  31. package/architecture/lib/graph-comparator.js +100 -0
  32. package/architecture/lib/graph-comparator.js.map +1 -0
  33. package/architecture/lib/graph-comparator.ts +141 -0
  34. package/architecture/lib/graph-generator.d.ts +19 -0
  35. package/architecture/lib/graph-generator.js +88 -0
  36. package/architecture/lib/graph-generator.js.map +1 -0
  37. package/architecture/lib/graph-generator.ts +102 -0
  38. package/architecture/lib/graph-loader.d.ts +31 -0
  39. package/architecture/lib/graph-loader.js +70 -0
  40. package/architecture/lib/graph-loader.js.map +1 -0
  41. package/architecture/lib/graph-loader.ts +82 -0
  42. package/architecture/lib/graph-sorter.d.ts +37 -0
  43. package/architecture/lib/graph-sorter.js +110 -0
  44. package/architecture/lib/graph-sorter.js.map +1 -0
  45. package/architecture/lib/graph-sorter.ts +137 -0
  46. package/architecture/lib/graph-visualizer.d.ts +29 -0
  47. package/architecture/lib/graph-visualizer.js +209 -0
  48. package/architecture/lib/graph-visualizer.js.map +1 -0
  49. package/architecture/lib/graph-visualizer.ts +222 -0
  50. package/architecture/lib/package-validator.d.ts +38 -0
  51. package/architecture/lib/package-validator.js +105 -0
  52. package/architecture/lib/package-validator.js.map +1 -0
  53. package/architecture/lib/package-validator.ts +144 -0
  54. package/config/eslint/base.mjs +6 -0
  55. package/eslint-plugin/__tests__/max-file-lines.test.ts +207 -0
  56. package/eslint-plugin/__tests__/max-method-lines.test.ts +258 -0
  57. package/eslint-plugin/__tests__/no-unmanaged-exceptions.test.ts +359 -0
  58. package/eslint-plugin/index.d.ts +11 -0
  59. package/eslint-plugin/index.js +15 -0
  60. package/eslint-plugin/index.js.map +1 -1
  61. package/eslint-plugin/index.ts +15 -0
  62. package/eslint-plugin/rules/enforce-architecture.d.ts +15 -0
  63. package/eslint-plugin/rules/enforce-architecture.js +406 -0
  64. package/eslint-plugin/rules/enforce-architecture.js.map +1 -0
  65. package/eslint-plugin/rules/enforce-architecture.ts +469 -0
  66. package/eslint-plugin/rules/max-file-lines.d.ts +12 -0
  67. package/eslint-plugin/rules/max-file-lines.js +257 -0
  68. package/eslint-plugin/rules/max-file-lines.js.map +1 -0
  69. package/eslint-plugin/rules/max-file-lines.ts +272 -0
  70. package/eslint-plugin/rules/max-method-lines.d.ts +12 -0
  71. package/eslint-plugin/rules/max-method-lines.js +240 -0
  72. package/eslint-plugin/rules/max-method-lines.js.map +1 -0
  73. package/eslint-plugin/rules/max-method-lines.ts +287 -0
  74. package/eslint-plugin/rules/no-unmanaged-exceptions.d.ts +22 -0
  75. package/eslint-plugin/rules/no-unmanaged-exceptions.js +605 -0
  76. package/eslint-plugin/rules/no-unmanaged-exceptions.js.map +1 -0
  77. package/eslint-plugin/rules/no-unmanaged-exceptions.ts +621 -0
  78. package/executors.json +29 -0
  79. package/package.json +13 -3
  80. package/plugins/circular-deps/index.d.ts +8 -0
  81. package/plugins/circular-deps/index.js +14 -0
  82. package/plugins/circular-deps/index.js.map +1 -0
  83. package/plugins/circular-deps/index.ts +9 -0
  84. package/plugins/circular-deps/plugin.d.ts +32 -0
  85. package/plugins/circular-deps/plugin.js +73 -0
  86. package/plugins/circular-deps/plugin.js.map +1 -0
  87. package/plugins/circular-deps/plugin.ts +83 -0
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ /**
3
+ * Validate No Skip-Level Dependencies Executor
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).
8
+ *
9
+ * This keeps the architecture graph clean for visualization and human understanding.
10
+ *
11
+ * Usage:
12
+ * nx run architecture:validate-no-skiplevel-deps
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.default = runExecutor;
16
+ const tslib_1 = require("tslib");
17
+ const graph_generator_1 = require("../../lib/graph-generator");
18
+ const fs = tslib_1.__importStar(require("fs"));
19
+ const path = tslib_1.__importStar(require("path"));
20
+ const TRANSITIVE_DEPS_DOC = `# AI Agent Instructions: Redundant Transitive Dependency Violation
21
+
22
+ **READ THIS FILE FIRST before making any changes!**
23
+
24
+ ## Why This Rule Exists
25
+
26
+ This rule keeps the architecture dependency graph **CLEAN and SIMPLE**.
27
+
28
+ When you run \`npx nx run architecture:visualize\`, it generates a visual diagram of all
29
+ package dependencies. Without this rule, you end up with a tangled mess of 100+ lines
30
+ where everything depends on everything - making it impossible to understand.
31
+
32
+ **Clean graphs = easier understanding for humans AND AI agents.**
33
+
34
+ ## Understanding the Error
35
+
36
+ You have a **redundant transitive dependency**. This means:
37
+
38
+ 1. Project A directly depends on Project C
39
+ 2. BUT Project A also depends on Project B
40
+ 3. AND Project B already brings in Project C (transitively)
41
+
42
+ Therefore, Project A's direct dependency on C is **redundant** - it's already available
43
+ through B. This extra line clutters the dependency graph.
44
+
45
+ **Example:**
46
+ \`\`\`
47
+ http-server depends on: [http-routing, http-filters, core-util]
48
+ ^^^^^^^^^ ^^^^^^^^
49
+ REDUNDANT! REDUNDANT!
50
+
51
+ Why? Because http-routing already brings in:
52
+ - http-filters (direct)
53
+ - core-util (via http-api)
54
+ \`\`\`
55
+
56
+ ## How to Fix
57
+
58
+ ### Step 1: Identify the Redundant Dependency
59
+
60
+ Look at the error message. It tells you:
61
+ - Which project has the problem
62
+ - Which dependency is redundant
63
+ - Which other dependency already brings it in
64
+
65
+ ### Step 2: Remove from project.json
66
+
67
+ Remove the redundant dependency from \`build.dependsOn\`:
68
+
69
+ \`\`\`json
70
+ {
71
+ "targets": {
72
+ "build": {
73
+ "dependsOn": [
74
+ "^build",
75
+ "http-routing:build"
76
+ // REMOVE: "http-filters:build" <-- redundant, http-routing brings it in
77
+ // REMOVE: "core-util:build" <-- redundant, http-routing brings it in
78
+ ]
79
+ }
80
+ }
81
+ }
82
+ \`\`\`
83
+
84
+ ### Step 3: Remove from package.json
85
+
86
+ Remove the redundant dependency from \`dependencies\`:
87
+
88
+ \`\`\`json
89
+ {
90
+ "dependencies": {
91
+ "@webpieces/http-routing": "*"
92
+ // REMOVE: "@webpieces/http-filters": "*" <-- redundant
93
+ // REMOVE: "@webpieces/core-util": "*" <-- redundant
94
+ }
95
+ }
96
+ \`\`\`
97
+
98
+ ### Step 4: Regenerate Architecture
99
+
100
+ \`\`\`bash
101
+ npx nx run architecture:generate
102
+ \`\`\`
103
+
104
+ ### Step 5: Verify
105
+
106
+ \`\`\`bash
107
+ npm run build-all
108
+ \`\`\`
109
+
110
+ ## Important Notes
111
+
112
+ - You DON'T lose access to the transitive dependency - it's still available through the parent
113
+ - This is about keeping the DECLARED dependencies minimal and clean
114
+ - The actual runtime/compile behavior is unchanged
115
+ - TypeScript will still find the types through the transitive path
116
+
117
+ ## Remember
118
+
119
+ - Fewer lines in the graph = easier to understand
120
+ - Only declare what you DIRECTLY need that isn't already transitively available
121
+ - When in doubt, check with \`npx nx run architecture:visualize\`
122
+ `;
123
+ /**
124
+ * Compute all transitive dependencies for a project
125
+ */
126
+ function computeTransitiveDeps(project, graph, visited = new Set()) {
127
+ const result = new Set();
128
+ if (visited.has(project)) {
129
+ return result;
130
+ }
131
+ visited.add(project);
132
+ const directDeps = graph[project] || [];
133
+ for (const dep of directDeps) {
134
+ result.add(dep);
135
+ // Recursively get transitive deps
136
+ const transitive = computeTransitiveDeps(dep, graph, visited);
137
+ for (const t of transitive) {
138
+ result.add(t);
139
+ }
140
+ }
141
+ return result;
142
+ }
143
+ /**
144
+ * Find redundant dependencies for a project
145
+ */
146
+ function findRedundantDeps(project, graph) {
147
+ const redundant = [];
148
+ const directDeps = graph[project] || [];
149
+ // For each direct dependency, compute what it transitively brings in
150
+ const transitiveByDep = new Map();
151
+ for (const dep of directDeps) {
152
+ transitiveByDep.set(dep, computeTransitiveDeps(dep, graph));
153
+ }
154
+ // Check if any direct dependency is already brought in by another
155
+ for (const dep of directDeps) {
156
+ for (const [otherDep, otherTransitive] of transitiveByDep) {
157
+ if (otherDep !== dep && otherTransitive.has(dep)) {
158
+ redundant.push({
159
+ project,
160
+ redundantDep: dep,
161
+ alreadyBroughtInBy: otherDep,
162
+ });
163
+ break; // Only report once per redundant dep
164
+ }
165
+ }
166
+ }
167
+ return redundant;
168
+ }
169
+ /**
170
+ * Write documentation file when violations are found
171
+ */
172
+ function writeDocFile(workspaceRoot) {
173
+ const docPath = path.join(workspaceRoot, 'tmp', 'webpieces', 'webpieces.transitivedeps.md');
174
+ const docDir = path.dirname(docPath);
175
+ try {
176
+ fs.mkdirSync(docDir, { recursive: true });
177
+ fs.writeFileSync(docPath, TRANSITIVE_DEPS_DOC, 'utf-8');
178
+ }
179
+ catch (err) {
180
+ void err;
181
+ console.warn(`Could not write documentation file: ${docPath}`);
182
+ }
183
+ }
184
+ async function runExecutor(_options, context) {
185
+ console.log('\nšŸ”„ Validating No Skip-Level Dependencies\n');
186
+ try {
187
+ // Step 1: Generate current graph from project.json files
188
+ console.log('šŸ“Š Generating dependency graph from project.json files...');
189
+ const graph = await (0, graph_generator_1.generateGraph)();
190
+ // Step 2: Find all redundant dependencies
191
+ console.log('šŸ” Checking for redundant transitive dependencies...');
192
+ const allRedundant = [];
193
+ for (const project of Object.keys(graph)) {
194
+ const redundant = findRedundantDeps(project, graph);
195
+ allRedundant.push(...redundant);
196
+ }
197
+ if (allRedundant.length === 0) {
198
+ console.log('āœ… No redundant transitive dependencies detected!');
199
+ console.log('\nšŸ“ˆ Graph is clean and minimal.');
200
+ return { success: true };
201
+ }
202
+ // Write documentation file
203
+ const workspaceRoot = context.root || process.cwd();
204
+ writeDocFile(workspaceRoot);
205
+ // Report violations
206
+ console.error('\nāŒ Redundant transitive dependencies detected!\n');
207
+ console.error('āš ļø AI Agent: READ tmp/webpieces/webpieces.transitivedeps.md for fix instructions!\n');
208
+ for (const r of allRedundant) {
209
+ console.error(` ${r.project}:`);
210
+ console.error(` └─ "${r.redundantDep}" is REDUNDANT`);
211
+ console.error(` (already brought in by "${r.alreadyBroughtInBy}")\n`);
212
+ }
213
+ console.error('\nTo fix:');
214
+ console.error(' 1. READ tmp/webpieces/webpieces.transitivedeps.md');
215
+ console.error(' 2. Remove redundant deps from project.json build.dependsOn');
216
+ console.error(' 3. Remove redundant deps from package.json dependencies');
217
+ console.error(' 4. Run: npx nx run architecture:generate');
218
+ console.error(' 5. Run: npm run build-all');
219
+ return { success: false };
220
+ }
221
+ catch (err) {
222
+ const error = err instanceof Error ? err : new Error(String(err));
223
+ console.error('āŒ Skip-level validation failed:', error.message);
224
+ return { success: false };
225
+ }
226
+ }
227
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/architecture/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 * as fs from 'fs';\nimport * as path from 'path';\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\nconst TRANSITIVE_DEPS_DOC = `# AI Agent Instructions: Redundant Transitive Dependency Violation\n\n**READ THIS FILE FIRST before making any changes!**\n\n## Why This Rule Exists\n\nThis rule keeps the architecture dependency graph **CLEAN and SIMPLE**.\n\nWhen you run \\`npx nx run architecture:visualize\\`, it generates a visual diagram of all\npackage dependencies. Without this rule, you end up with a tangled mess of 100+ lines\nwhere everything depends on everything - making it impossible to understand.\n\n**Clean graphs = easier understanding for humans AND AI agents.**\n\n## Understanding the Error\n\nYou have a **redundant transitive dependency**. This means:\n\n1. Project A directly depends on Project C\n2. BUT Project A also depends on Project B\n3. AND Project B already brings in Project C (transitively)\n\nTherefore, Project A's direct dependency on C is **redundant** - it's already available\nthrough B. This extra line clutters the dependency graph.\n\n**Example:**\n\\`\\`\\`\nhttp-server depends on: [http-routing, http-filters, core-util]\n ^^^^^^^^^ ^^^^^^^^\n REDUNDANT! REDUNDANT!\n\nWhy? Because http-routing already brings in:\n - http-filters (direct)\n - core-util (via http-api)\n\\`\\`\\`\n\n## How to Fix\n\n### Step 1: Identify the Redundant Dependency\n\nLook at the error message. It tells you:\n- Which project has the problem\n- Which dependency is redundant\n- Which other dependency already brings it in\n\n### Step 2: Remove from project.json\n\nRemove the redundant dependency from \\`build.dependsOn\\`:\n\n\\`\\`\\`json\n{\n \"targets\": {\n \"build\": {\n \"dependsOn\": [\n \"^build\",\n \"http-routing:build\"\n // REMOVE: \"http-filters:build\" <-- redundant, http-routing brings it in\n // REMOVE: \"core-util:build\" <-- redundant, http-routing brings it in\n ]\n }\n }\n}\n\\`\\`\\`\n\n### Step 3: Remove from package.json\n\nRemove the redundant dependency from \\`dependencies\\`:\n\n\\`\\`\\`json\n{\n \"dependencies\": {\n \"@webpieces/http-routing\": \"*\"\n // REMOVE: \"@webpieces/http-filters\": \"*\" <-- redundant\n // REMOVE: \"@webpieces/core-util\": \"*\" <-- redundant\n }\n}\n\\`\\`\\`\n\n### Step 4: Regenerate Architecture\n\n\\`\\`\\`bash\nnpx nx run architecture:generate\n\\`\\`\\`\n\n### Step 5: Verify\n\n\\`\\`\\`bash\nnpm run build-all\n\\`\\`\\`\n\n## Important Notes\n\n- You DON'T lose access to the transitive dependency - it's still available through the parent\n- This is about keeping the DECLARED dependencies minimal and clean\n- The actual runtime/compile behavior is unchanged\n- TypeScript will still find the types through the transitive path\n\n## Remember\n\n- Fewer lines in the graph = easier to understand\n- Only declare what you DIRECTLY need that isn't already transitively available\n- When in doubt, check with \\`npx nx run architecture:visualize\\`\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 for (const dep of directDeps) {\n for (const [otherDep, otherTransitive] of transitiveByDep) {\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 const docPath = path.join(workspaceRoot, 'tmp', 'webpieces', 'webpieces.transitivedeps.md');\n const docDir = path.dirname(docPath);\n\n try {\n fs.mkdirSync(docDir, { recursive: true });\n fs.writeFileSync(docPath, TRANSITIVE_DEPS_DOC, 'utf-8');\n } catch (err: any) {\n void err;\n console.warn(`Could not write documentation file: ${docPath}`);\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 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 tmp/webpieces/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 tmp/webpieces/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: any) {\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('āŒ Skip-level validation failed:', error.message);\n return { success: false };\n }\n}\n"]}
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Validate No Skip-Level Dependencies Executor
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).
7
+ *
8
+ * This keeps the architecture graph clean for visualization and human understanding.
9
+ *
10
+ * Usage:
11
+ * nx run architecture:validate-no-skiplevel-deps
12
+ */
13
+
14
+ import type { ExecutorContext } from '@nx/devkit';
15
+ import { generateGraph } from '../../lib/graph-generator';
16
+ import * as fs from 'fs';
17
+ import * as path from 'path';
18
+
19
+ export interface ValidateNoSkipLevelDepsOptions {
20
+ // No options needed
21
+ }
22
+
23
+ export interface ExecutorResult {
24
+ success: boolean;
25
+ }
26
+
27
+ interface RedundantDep {
28
+ project: string;
29
+ redundantDep: string;
30
+ alreadyBroughtInBy: string;
31
+ }
32
+
33
+ const TRANSITIVE_DEPS_DOC = `# AI Agent Instructions: Redundant Transitive Dependency Violation
34
+
35
+ **READ THIS FILE FIRST before making any changes!**
36
+
37
+ ## Why This Rule Exists
38
+
39
+ This rule keeps the architecture dependency graph **CLEAN and SIMPLE**.
40
+
41
+ When you run \`npx nx run architecture:visualize\`, it generates a visual diagram of all
42
+ package dependencies. Without this rule, you end up with a tangled mess of 100+ lines
43
+ where everything depends on everything - making it impossible to understand.
44
+
45
+ **Clean graphs = easier understanding for humans AND AI agents.**
46
+
47
+ ## Understanding the Error
48
+
49
+ You have a **redundant transitive dependency**. This means:
50
+
51
+ 1. Project A directly depends on Project C
52
+ 2. BUT Project A also depends on Project B
53
+ 3. AND Project B already brings in Project C (transitively)
54
+
55
+ Therefore, Project A's direct dependency on C is **redundant** - it's already available
56
+ through B. This extra line clutters the dependency graph.
57
+
58
+ **Example:**
59
+ \`\`\`
60
+ http-server depends on: [http-routing, http-filters, core-util]
61
+ ^^^^^^^^^ ^^^^^^^^
62
+ REDUNDANT! REDUNDANT!
63
+
64
+ Why? Because http-routing already brings in:
65
+ - http-filters (direct)
66
+ - core-util (via http-api)
67
+ \`\`\`
68
+
69
+ ## How to Fix
70
+
71
+ ### Step 1: Identify the Redundant Dependency
72
+
73
+ Look at the error message. It tells you:
74
+ - Which project has the problem
75
+ - Which dependency is redundant
76
+ - Which other dependency already brings it in
77
+
78
+ ### Step 2: Remove from project.json
79
+
80
+ Remove the redundant dependency from \`build.dependsOn\`:
81
+
82
+ \`\`\`json
83
+ {
84
+ "targets": {
85
+ "build": {
86
+ "dependsOn": [
87
+ "^build",
88
+ "http-routing:build"
89
+ // REMOVE: "http-filters:build" <-- redundant, http-routing brings it in
90
+ // REMOVE: "core-util:build" <-- redundant, http-routing brings it in
91
+ ]
92
+ }
93
+ }
94
+ }
95
+ \`\`\`
96
+
97
+ ### Step 3: Remove from package.json
98
+
99
+ Remove the redundant dependency from \`dependencies\`:
100
+
101
+ \`\`\`json
102
+ {
103
+ "dependencies": {
104
+ "@webpieces/http-routing": "*"
105
+ // REMOVE: "@webpieces/http-filters": "*" <-- redundant
106
+ // REMOVE: "@webpieces/core-util": "*" <-- redundant
107
+ }
108
+ }
109
+ \`\`\`
110
+
111
+ ### Step 4: Regenerate Architecture
112
+
113
+ \`\`\`bash
114
+ npx nx run architecture:generate
115
+ \`\`\`
116
+
117
+ ### Step 5: Verify
118
+
119
+ \`\`\`bash
120
+ npm run build-all
121
+ \`\`\`
122
+
123
+ ## Important Notes
124
+
125
+ - You DON'T lose access to the transitive dependency - it's still available through the parent
126
+ - This is about keeping the DECLARED dependencies minimal and clean
127
+ - The actual runtime/compile behavior is unchanged
128
+ - TypeScript will still find the types through the transitive path
129
+
130
+ ## Remember
131
+
132
+ - Fewer lines in the graph = easier to understand
133
+ - Only declare what you DIRECTLY need that isn't already transitively available
134
+ - When in doubt, check with \`npx nx run architecture:visualize\`
135
+ `;
136
+
137
+ /**
138
+ * Compute all transitive dependencies for a project
139
+ */
140
+ function computeTransitiveDeps(
141
+ project: string,
142
+ graph: Record<string, string[]>,
143
+ visited: Set<string> = new Set()
144
+ ): Set<string> {
145
+ const result = new Set<string>();
146
+
147
+ if (visited.has(project)) {
148
+ return result;
149
+ }
150
+ visited.add(project);
151
+
152
+ const directDeps = graph[project] || [];
153
+ for (const dep of directDeps) {
154
+ result.add(dep);
155
+ // Recursively get transitive deps
156
+ const transitive = computeTransitiveDeps(dep, graph, visited);
157
+ for (const t of transitive) {
158
+ result.add(t);
159
+ }
160
+ }
161
+
162
+ return result;
163
+ }
164
+
165
+ /**
166
+ * Find redundant dependencies for a project
167
+ */
168
+ function findRedundantDeps(
169
+ project: string,
170
+ graph: Record<string, string[]>
171
+ ): RedundantDep[] {
172
+ const redundant: RedundantDep[] = [];
173
+ const directDeps = graph[project] || [];
174
+
175
+ // For each direct dependency, compute what it transitively brings in
176
+ const transitiveByDep = new Map<string, Set<string>>();
177
+ for (const dep of directDeps) {
178
+ transitiveByDep.set(dep, computeTransitiveDeps(dep, graph));
179
+ }
180
+
181
+ // Check if any direct dependency is already brought in by another
182
+ for (const dep of directDeps) {
183
+ for (const [otherDep, otherTransitive] of transitiveByDep) {
184
+ if (otherDep !== dep && otherTransitive.has(dep)) {
185
+ redundant.push({
186
+ project,
187
+ redundantDep: dep,
188
+ alreadyBroughtInBy: otherDep,
189
+ });
190
+ break; // Only report once per redundant dep
191
+ }
192
+ }
193
+ }
194
+
195
+ return redundant;
196
+ }
197
+
198
+ /**
199
+ * Write documentation file when violations are found
200
+ */
201
+ function writeDocFile(workspaceRoot: string): void {
202
+ const docPath = path.join(workspaceRoot, 'tmp', 'webpieces', 'webpieces.transitivedeps.md');
203
+ const docDir = path.dirname(docPath);
204
+
205
+ try {
206
+ fs.mkdirSync(docDir, { recursive: true });
207
+ fs.writeFileSync(docPath, TRANSITIVE_DEPS_DOC, 'utf-8');
208
+ } catch (err: any) {
209
+ void err;
210
+ console.warn(`Could not write documentation file: ${docPath}`);
211
+ }
212
+ }
213
+
214
+ export default async function runExecutor(
215
+ _options: ValidateNoSkipLevelDepsOptions,
216
+ context: ExecutorContext
217
+ ): Promise<ExecutorResult> {
218
+ console.log('\nšŸ”„ Validating No Skip-Level Dependencies\n');
219
+
220
+ try {
221
+ // Step 1: Generate current graph from project.json files
222
+ console.log('šŸ“Š Generating dependency graph from project.json files...');
223
+ const graph = await generateGraph();
224
+
225
+ // Step 2: Find all redundant dependencies
226
+ console.log('šŸ” Checking for redundant transitive dependencies...');
227
+ const allRedundant: RedundantDep[] = [];
228
+
229
+ for (const project of Object.keys(graph)) {
230
+ const redundant = findRedundantDeps(project, graph);
231
+ allRedundant.push(...redundant);
232
+ }
233
+
234
+ if (allRedundant.length === 0) {
235
+ console.log('āœ… No redundant transitive dependencies detected!');
236
+ console.log('\nšŸ“ˆ Graph is clean and minimal.');
237
+ return { success: true };
238
+ }
239
+
240
+ // Write documentation file
241
+ const workspaceRoot = context.root || process.cwd();
242
+ writeDocFile(workspaceRoot);
243
+
244
+ // Report violations
245
+ console.error('\nāŒ Redundant transitive dependencies detected!\n');
246
+ console.error('āš ļø AI Agent: READ tmp/webpieces/webpieces.transitivedeps.md for fix instructions!\n');
247
+
248
+ for (const r of allRedundant) {
249
+ console.error(` ${r.project}:`);
250
+ console.error(` └─ "${r.redundantDep}" is REDUNDANT`);
251
+ console.error(` (already brought in by "${r.alreadyBroughtInBy}")\n`);
252
+ }
253
+
254
+ console.error('\nTo fix:');
255
+ console.error(' 1. READ tmp/webpieces/webpieces.transitivedeps.md');
256
+ console.error(' 2. Remove redundant deps from project.json build.dependsOn');
257
+ console.error(' 3. Remove redundant deps from package.json dependencies');
258
+ console.error(' 4. Run: npx nx run architecture:generate');
259
+ console.error(' 5. Run: npm run build-all');
260
+
261
+ return { success: false };
262
+ } catch (err: any) {
263
+ const error = err instanceof Error ? err : new Error(String(err));
264
+ console.error('āŒ Skip-level validation failed:', error.message);
265
+ return { success: false };
266
+ }
267
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "title": "Validate No Skip-Level Dependencies Executor",
4
+ "description": "Validates that no project has redundant transitive dependencies",
5
+ "type": "object",
6
+ "properties": {},
7
+ "required": []
8
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Visualize Executor
3
+ *
4
+ * Generates visual representations of the architecture graph (DOT + HTML)
5
+ * and opens the visualization in a browser.
6
+ *
7
+ * Usage:
8
+ * nx run architecture:visualize
9
+ */
10
+ import type { ExecutorContext } from '@nx/devkit';
11
+ export interface VisualizeExecutorOptions {
12
+ graphPath?: string;
13
+ }
14
+ export interface ExecutorResult {
15
+ success: boolean;
16
+ }
17
+ export default function runExecutor(options: VisualizeExecutorOptions, context: ExecutorContext): Promise<ExecutorResult>;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ /**
3
+ * Visualize Executor
4
+ *
5
+ * Generates visual representations of the architecture graph (DOT + HTML)
6
+ * and opens the visualization in a browser.
7
+ *
8
+ * Usage:
9
+ * nx run architecture:visualize
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.default = runExecutor;
13
+ const graph_loader_1 = require("../../lib/graph-loader");
14
+ const graph_visualizer_1 = require("../../lib/graph-visualizer");
15
+ async function runExecutor(options, context) {
16
+ const { graphPath } = options;
17
+ const workspaceRoot = context.root;
18
+ console.log('\nšŸŽØ Architecture Visualization\n');
19
+ try {
20
+ // Load the saved graph
21
+ console.log('šŸ“‚ Loading saved graph...');
22
+ const graph = (0, graph_loader_1.loadBlessedGraph)(workspaceRoot, graphPath);
23
+ if (!graph) {
24
+ console.error('āŒ No saved graph found at architecture/dependencies.json');
25
+ console.error(' Run: nx run architecture:generate first');
26
+ return { success: false };
27
+ }
28
+ // Generate visualization
29
+ console.log('šŸŽØ Generating visualization...');
30
+ const { dotPath, htmlPath } = (0, graph_visualizer_1.writeVisualization)(graph, workspaceRoot);
31
+ console.log(`āœ… Generated: ${dotPath}`);
32
+ console.log(`āœ… Generated: ${htmlPath}`);
33
+ // Try to open in browser
34
+ console.log('\n🌐 Opening visualization in browser...');
35
+ if ((0, graph_visualizer_1.openVisualization)(htmlPath)) {
36
+ console.log('āœ… Browser opened');
37
+ }
38
+ else {
39
+ console.log(`āš ļø Could not auto-open. Open manually: ${htmlPath}`);
40
+ }
41
+ return { success: true };
42
+ }
43
+ catch (err) {
44
+ const error = err instanceof Error ? err : new Error(String(err));
45
+ console.error('āŒ Visualization failed:', error.message);
46
+ return { success: false };
47
+ }
48
+ }
49
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/architecture/executors/visualize/executor.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;AAcH,8BAwCC;AAnDD,yDAA0D;AAC1D,iEAAmF;AAUpE,KAAK,UAAU,WAAW,CACrC,OAAiC,EACjC,OAAwB;IAExB,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAC9B,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAEnC,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IAEjD,IAAI,CAAC;QACD,uBAAuB;QACvB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,IAAA,+BAAgB,EAAC,aAAa,EAAE,SAAS,CAAC,CAAC;QAEzD,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;YAC1E,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC5D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC9B,CAAC;QAED,yBAAyB;QACzB,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;QAC9C,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAA,qCAAkB,EAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,gBAAgB,OAAO,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,EAAE,CAAC,CAAC;QAExC,yBAAyB;QACzB,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACxD,IAAI,IAAA,oCAAiB,EAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,GAAG,CAAC,2CAA2C,QAAQ,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACxD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;AACL,CAAC","sourcesContent":["/**\n * Visualize Executor\n *\n * Generates visual representations of the architecture graph (DOT + HTML)\n * and opens the visualization in a browser.\n *\n * Usage:\n * nx run architecture:visualize\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { loadBlessedGraph } from '../../lib/graph-loader';\nimport { writeVisualization, openVisualization } from '../../lib/graph-visualizer';\n\nexport interface VisualizeExecutorOptions {\n graphPath?: string;\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nexport default async function runExecutor(\n options: VisualizeExecutorOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const { graphPath } = options;\n const workspaceRoot = context.root;\n\n console.log('\\nšŸŽØ Architecture Visualization\\n');\n\n try {\n // Load the saved graph\n console.log('šŸ“‚ Loading saved graph...');\n const graph = loadBlessedGraph(workspaceRoot, graphPath);\n\n if (!graph) {\n console.error('āŒ No saved graph found at architecture/dependencies.json');\n console.error(' Run: nx run architecture:generate first');\n return { success: false };\n }\n\n // Generate visualization\n console.log('šŸŽØ Generating visualization...');\n const { dotPath, htmlPath } = writeVisualization(graph, workspaceRoot);\n console.log(`āœ… Generated: ${dotPath}`);\n console.log(`āœ… Generated: ${htmlPath}`);\n\n // Try to open in browser\n console.log('\\n🌐 Opening visualization in browser...');\n if (openVisualization(htmlPath)) {\n console.log('āœ… Browser opened');\n } else {\n console.log(`āš ļø Could not auto-open. Open manually: ${htmlPath}`);\n }\n\n return { success: true };\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n console.error('āŒ Visualization failed:', error.message);\n return { success: false };\n }\n}\n"]}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Visualize Executor
3
+ *
4
+ * Generates visual representations of the architecture graph (DOT + HTML)
5
+ * and opens the visualization in a browser.
6
+ *
7
+ * Usage:
8
+ * nx run architecture:visualize
9
+ */
10
+
11
+ import type { ExecutorContext } from '@nx/devkit';
12
+ import { loadBlessedGraph } from '../../lib/graph-loader';
13
+ import { writeVisualization, openVisualization } from '../../lib/graph-visualizer';
14
+
15
+ export interface VisualizeExecutorOptions {
16
+ graphPath?: string;
17
+ }
18
+
19
+ export interface ExecutorResult {
20
+ success: boolean;
21
+ }
22
+
23
+ export default async function runExecutor(
24
+ options: VisualizeExecutorOptions,
25
+ context: ExecutorContext
26
+ ): Promise<ExecutorResult> {
27
+ const { graphPath } = options;
28
+ const workspaceRoot = context.root;
29
+
30
+ console.log('\nšŸŽØ Architecture Visualization\n');
31
+
32
+ try {
33
+ // Load the saved graph
34
+ console.log('šŸ“‚ Loading saved graph...');
35
+ const graph = loadBlessedGraph(workspaceRoot, graphPath);
36
+
37
+ if (!graph) {
38
+ console.error('āŒ No saved graph found at architecture/dependencies.json');
39
+ console.error(' Run: nx run architecture:generate first');
40
+ return { success: false };
41
+ }
42
+
43
+ // Generate visualization
44
+ console.log('šŸŽØ Generating visualization...');
45
+ const { dotPath, htmlPath } = writeVisualization(graph, workspaceRoot);
46
+ console.log(`āœ… Generated: ${dotPath}`);
47
+ console.log(`āœ… Generated: ${htmlPath}`);
48
+
49
+ // Try to open in browser
50
+ console.log('\n🌐 Opening visualization in browser...');
51
+ if (openVisualization(htmlPath)) {
52
+ console.log('āœ… Browser opened');
53
+ } else {
54
+ console.log(`āš ļø Could not auto-open. Open manually: ${htmlPath}`);
55
+ }
56
+
57
+ return { success: true };
58
+ } catch (err: unknown) {
59
+ const error = err instanceof Error ? err : new Error(String(err));
60
+ console.error('āŒ Visualization failed:', error.message);
61
+ return { success: false };
62
+ }
63
+ }