@webpieces/nx-webpieces-rules 0.0.1 → 0.2.113

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 (119) hide show
  1. package/package.json +5 -4
  2. package/src/executor-result.d.ts +4 -0
  3. package/src/executor-result.js +10 -0
  4. package/src/executor-result.js.map +1 -0
  5. package/src/executors/generate/executor.d.ts +16 -0
  6. package/src/executors/generate/{executor.ts → executor.js} +15 -30
  7. package/src/executors/generate/executor.js.map +1 -0
  8. package/src/executors/help/executor.d.ts +8 -0
  9. package/src/executors/help/{executor.ts → executor.js} +5 -12
  10. package/src/executors/help/executor.js.map +1 -0
  11. package/src/executors/validate-architecture-unchanged/executor.d.ts +17 -0
  12. package/src/executors/validate-architecture-unchanged/{executor.ts → executor.js} +24 -46
  13. package/src/executors/validate-architecture-unchanged/executor.js.map +1 -0
  14. package/src/executors/validate-catch-error-pattern/executor.d.ts +3 -0
  15. package/src/executors/validate-catch-error-pattern/executor.js +10 -0
  16. package/src/executors/validate-catch-error-pattern/executor.js.map +1 -0
  17. package/src/executors/validate-code/executor.d.ts +3 -0
  18. package/src/executors/validate-code/executor.js +10 -0
  19. package/src/executors/validate-code/executor.js.map +1 -0
  20. package/src/executors/validate-dtos/executor.d.ts +3 -0
  21. package/src/executors/validate-dtos/executor.js +10 -0
  22. package/src/executors/validate-dtos/executor.js.map +1 -0
  23. package/src/executors/validate-eslint-sync/executor.d.ts +7 -0
  24. package/src/executors/validate-eslint-sync/{executor.ts → executor.js} +19 -37
  25. package/src/executors/validate-eslint-sync/executor.js.map +1 -0
  26. package/src/executors/validate-modified-files/executor.d.ts +3 -0
  27. package/src/executors/validate-modified-files/executor.js +10 -0
  28. package/src/executors/validate-modified-files/executor.js.map +1 -0
  29. package/src/executors/validate-modified-methods/executor.d.ts +3 -0
  30. package/src/executors/validate-modified-methods/executor.js +10 -0
  31. package/src/executors/validate-modified-methods/executor.js.map +1 -0
  32. package/src/executors/validate-new-methods/executor.d.ts +3 -0
  33. package/src/executors/validate-new-methods/executor.js +10 -0
  34. package/src/executors/validate-new-methods/executor.js.map +1 -0
  35. package/src/executors/validate-no-any-unknown/executor.d.ts +3 -0
  36. package/src/executors/validate-no-any-unknown/executor.js +10 -0
  37. package/src/executors/validate-no-any-unknown/executor.js.map +1 -0
  38. package/src/executors/validate-no-architecture-cycles/executor.d.ts +16 -0
  39. package/src/executors/validate-no-architecture-cycles/{executor.ts → executor.js} +16 -28
  40. package/src/executors/validate-no-architecture-cycles/executor.js.map +1 -0
  41. package/src/executors/validate-no-destructure/executor.d.ts +3 -0
  42. package/src/executors/validate-no-destructure/executor.js +10 -0
  43. package/src/executors/validate-no-destructure/executor.js.map +1 -0
  44. package/src/executors/validate-no-direct-api-resolver/executor.d.ts +3 -0
  45. package/src/executors/validate-no-direct-api-resolver/executor.js +10 -0
  46. package/src/executors/validate-no-direct-api-resolver/executor.js.map +1 -0
  47. package/src/executors/validate-no-implicit-any/executor.d.ts +3 -0
  48. package/src/executors/validate-no-implicit-any/executor.js +10 -0
  49. package/src/executors/validate-no-implicit-any/executor.js.map +1 -0
  50. package/src/executors/validate-no-inline-types/executor.d.ts +3 -0
  51. package/src/executors/validate-no-inline-types/executor.js +10 -0
  52. package/src/executors/validate-no-inline-types/executor.js.map +1 -0
  53. package/src/executors/validate-no-skiplevel-deps/executor.d.ts +19 -0
  54. package/src/executors/validate-no-skiplevel-deps/{executor.ts → executor.js} +23 -63
  55. package/src/executors/validate-no-skiplevel-deps/executor.js.map +1 -0
  56. package/src/executors/validate-no-unmanaged-exceptions/executor.d.ts +3 -0
  57. package/src/executors/validate-no-unmanaged-exceptions/executor.js +10 -0
  58. package/src/executors/validate-no-unmanaged-exceptions/executor.js.map +1 -0
  59. package/src/executors/validate-packagejson/executor.d.ts +16 -0
  60. package/src/executors/validate-packagejson/{executor.ts → executor.js} +15 -32
  61. package/src/executors/validate-packagejson/executor.js.map +1 -0
  62. package/src/executors/validate-prisma-converters/executor.d.ts +3 -0
  63. package/src/executors/validate-prisma-converters/executor.js +10 -0
  64. package/src/executors/validate-prisma-converters/executor.js.map +1 -0
  65. package/src/executors/validate-return-types/executor.d.ts +3 -0
  66. package/src/executors/validate-return-types/executor.js +10 -0
  67. package/src/executors/validate-return-types/executor.js.map +1 -0
  68. package/src/executors/validate-ts-in-src/executor.d.ts +32 -0
  69. package/src/executors/validate-ts-in-src/{executor.ts → executor.js} +80 -135
  70. package/src/executors/validate-ts-in-src/executor.js.map +1 -0
  71. package/src/executors/validate-versions-locked/executor.d.ts +22 -0
  72. package/src/executors/validate-versions-locked/{executor.ts → executor.js} +49 -116
  73. package/src/executors/validate-versions-locked/executor.js.map +1 -0
  74. package/src/executors/visualize/executor.d.ts +17 -0
  75. package/src/executors/visualize/{executor.ts → executor.js} +16 -30
  76. package/src/executors/visualize/executor.js.map +1 -0
  77. package/src/{index.ts → index.d.ts} +5 -1
  78. package/src/index.js +14 -0
  79. package/src/index.js.map +1 -0
  80. package/src/lib/graph-comparator.d.ts +39 -0
  81. package/src/lib/{graph-comparator.ts → graph-comparator.js} +18 -67
  82. package/src/lib/graph-comparator.js.map +1 -0
  83. package/src/lib/graph-generator.d.ts +19 -0
  84. package/src/lib/{graph-generator.ts → graph-generator.js} +17 -30
  85. package/src/lib/graph-generator.js.map +1 -0
  86. package/src/lib/graph-loader.d.ts +31 -0
  87. package/src/lib/{graph-loader.ts → graph-loader.js} +24 -42
  88. package/src/lib/graph-loader.js.map +1 -0
  89. package/src/lib/graph-sorter.d.ts +37 -0
  90. package/src/lib/{graph-sorter.ts → graph-sorter.js} +26 -53
  91. package/src/lib/graph-sorter.js.map +1 -0
  92. package/src/lib/graph-visualizer.d.ts +31 -0
  93. package/src/lib/{graph-visualizer.ts → graph-visualizer.js} +32 -56
  94. package/src/lib/graph-visualizer.js.map +1 -0
  95. package/src/lib/package-validator.d.ts +40 -0
  96. package/src/lib/{package-validator.ts → package-validator.js} +28 -88
  97. package/src/lib/package-validator.js.map +1 -0
  98. package/src/plugin.d.ts +86 -0
  99. package/src/{plugin.ts → plugin.js} +100 -255
  100. package/src/plugin.js.map +1 -0
  101. package/src/toError.d.ts +5 -0
  102. package/src/{toError.ts → toError.js} +7 -6
  103. package/src/toError.js.map +1 -0
  104. package/LICENSE +0 -373
  105. package/src/executor-result.ts +0 -7
  106. package/src/executors/validate-catch-error-pattern/executor.ts +0 -11
  107. package/src/executors/validate-code/executor.ts +0 -11
  108. package/src/executors/validate-dtos/executor.ts +0 -11
  109. package/src/executors/validate-modified-files/executor.ts +0 -11
  110. package/src/executors/validate-modified-methods/executor.ts +0 -11
  111. package/src/executors/validate-new-methods/executor.ts +0 -11
  112. package/src/executors/validate-no-any-unknown/executor.ts +0 -11
  113. package/src/executors/validate-no-destructure/executor.ts +0 -11
  114. package/src/executors/validate-no-direct-api-resolver/executor.ts +0 -11
  115. package/src/executors/validate-no-implicit-any/executor.ts +0 -11
  116. package/src/executors/validate-no-inline-types/executor.ts +0 -11
  117. package/src/executors/validate-no-unmanaged-exceptions/executor.ts +0 -11
  118. package/src/executors/validate-prisma-converters/executor.ts +0 -11
  119. package/src/executors/validate-return-types/executor.ts +0 -11
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Graph Sorter
3
4
  *
@@ -6,20 +7,9 @@
6
7
  * 2. Assign level numbers to each project (level 0 = no deps, level 1 = depends on level 0, etc.)
7
8
  * 3. Group projects into layers for deterministic ordering
8
9
  */
9
-
10
- /**
11
- * Graph entry with level metadata
12
- */
13
- export interface GraphEntry {
14
- level: number;
15
- dependsOn: string[];
16
- }
17
-
18
- /**
19
- * Enhanced graph format with level information
20
- */
21
- export type EnhancedGraph = Record<string, GraphEntry>;
22
-
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.computeTopologicalLayers = computeTopologicalLayers;
12
+ exports.sortGraphTopologically = sortGraphTopologically;
23
13
  /**
24
14
  * Compute topological layers for dependency graph using Kahn's algorithm
25
15
  *
@@ -29,88 +19,72 @@ export type EnhancedGraph = Record<string, GraphEntry>;
29
19
  * @param graph - Dependency graph { project: [deps] }
30
20
  * @returns Array of layers, each containing sorted project names
31
21
  */
32
- export function computeTopologicalLayers(graph: Record<string, string[]>): string[][] {
33
- const layers: string[][] = [];
34
- const processed = new Set<string>();
22
+ function computeTopologicalLayers(graph) {
23
+ const layers = [];
24
+ const processed = new Set();
35
25
  const allProjects = Object.keys(graph);
36
-
37
26
  while (processed.size < allProjects.length) {
38
- const currentLayer: string[] = [];
39
-
27
+ const currentLayer = [];
40
28
  for (const project of allProjects) {
41
- if (processed.has(project)) continue;
42
-
29
+ if (processed.has(project))
30
+ continue;
43
31
  const deps = graph[project] || [];
44
32
  // Check if all dependencies are in previous layers (already processed)
45
33
  const allDepsInPrevLayers = deps.every((dep) => processed.has(dep));
46
-
47
34
  if (allDepsInPrevLayers) {
48
35
  currentLayer.push(project);
49
36
  }
50
37
  }
51
-
52
38
  if (currentLayer.length === 0) {
53
39
  // No progress made = circular dependency detected
54
40
  const remaining = allProjects.filter((p) => !processed.has(p));
55
-
56
41
  // Try to identify the cycle
57
42
  const cycleInfo = findCycle(graph, remaining);
58
-
59
- throw new Error(
60
- `Circular dependency detected among: ${remaining.join(', ')}\n` +
61
- (cycleInfo ? `Cycle: ${cycleInfo}\n` : '') +
62
- 'Fix: Remove one of the dependencies to break the cycle.'
63
- );
43
+ throw new Error(`Circular dependency detected among: ${remaining.join(', ')}\n` +
44
+ (cycleInfo ? `Cycle: ${cycleInfo}\n` : '') +
45
+ 'Fix: Remove one of the dependencies to break the cycle.');
64
46
  }
65
-
66
47
  // Sort alphabetically within layer for deterministic output
67
48
  currentLayer.sort();
68
49
  layers.push(currentLayer);
69
-
70
50
  // Mark as processed
71
51
  currentLayer.forEach((p) => processed.add(p));
72
52
  }
73
-
74
53
  return layers;
75
54
  }
76
-
77
55
  /**
78
56
  * Try to find and describe a cycle in the graph
79
57
  */
80
- function findCycle(graph: Record<string, string[]>, remaining: string[]): string | null {
81
- const visited = new Set<string>();
82
- const path: string[] = [];
83
-
84
- function dfs(node: string): string | null {
58
+ function findCycle(graph, remaining) {
59
+ const visited = new Set();
60
+ const path = [];
61
+ function dfs(node) {
85
62
  if (path.includes(node)) {
86
63
  const cycleStart = path.indexOf(node);
87
64
  return [...path.slice(cycleStart), node].join(' -> ');
88
65
  }
89
- if (visited.has(node)) return null;
90
-
66
+ if (visited.has(node))
67
+ return null;
91
68
  visited.add(node);
92
69
  path.push(node);
93
-
94
70
  const deps = graph[node] || [];
95
71
  for (const dep of deps) {
96
72
  if (remaining.includes(dep)) {
97
73
  const result = dfs(dep);
98
- if (result) return result;
74
+ if (result)
75
+ return result;
99
76
  }
100
77
  }
101
-
102
78
  path.pop();
103
79
  return null;
104
80
  }
105
-
106
81
  for (const node of remaining) {
107
82
  const cycle = dfs(node);
108
- if (cycle) return cycle;
83
+ if (cycle)
84
+ return cycle;
109
85
  }
110
-
111
86
  return null;
112
87
  }
113
-
114
88
  /**
115
89
  * Sort graph in topological order with alphabetical sorting within layers
116
90
  * Returns enhanced format with level metadata
@@ -118,10 +92,9 @@ function findCycle(graph: Record<string, string[]>, remaining: string[]): string
118
92
  * @param graph - Unsorted dependency graph { project: [deps] }
119
93
  * @returns Sorted graph with level metadata { project: { level: number, dependsOn: [deps] } }
120
94
  */
121
- export function sortGraphTopologically(graph: Record<string, string[]>): EnhancedGraph {
95
+ function sortGraphTopologically(graph) {
122
96
  const layers = computeTopologicalLayers(graph);
123
- const result: EnhancedGraph = {};
124
-
97
+ const result = {};
125
98
  // Add projects layer by layer (dependencies before dependents)
126
99
  layers.forEach((layer, levelIndex) => {
127
100
  for (const project of layer) {
@@ -132,6 +105,6 @@ export function sortGraphTopologically(graph: Record<string, string[]>): Enhance
132
105
  };
133
106
  }
134
107
  });
135
-
136
108
  return result;
137
109
  }
110
+ //# sourceMappingURL=graph-sorter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-sorter.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-sorter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Graph Sorter\n *\n * Performs topological sorting on the dependency graph to:\n * 1. Detect circular dependencies (fails if cycle found)\n * 2. Assign level numbers to each project (level 0 = no deps, level 1 = depends on level 0, etc.)\n * 3. Group projects into layers for deterministic ordering\n */\n\n/**\n * Graph entry with level metadata\n */\nexport interface GraphEntry {\n level: number;\n dependsOn: string[];\n}\n\n/**\n * Enhanced graph format with level information\n */\nexport type EnhancedGraph = Record<string, GraphEntry>;\n\n/**\n * Compute topological layers for dependency graph using Kahn's algorithm\n *\n * Projects are grouped into layers where each layer only depends on previous layers.\n * Throws an error if a circular dependency is detected.\n *\n * @param graph - Dependency graph { project: [deps] }\n * @returns Array of layers, each containing sorted project names\n */\nexport function computeTopologicalLayers(graph: Record<string, string[]>): string[][] {\n const layers: string[][] = [];\n const processed = new Set<string>();\n const allProjects = Object.keys(graph);\n\n while (processed.size < allProjects.length) {\n const currentLayer: string[] = [];\n\n for (const project of allProjects) {\n if (processed.has(project)) continue;\n\n const deps = graph[project] || [];\n // Check if all dependencies are in previous layers (already processed)\n const allDepsInPrevLayers = deps.every((dep) => processed.has(dep));\n\n if (allDepsInPrevLayers) {\n currentLayer.push(project);\n }\n }\n\n if (currentLayer.length === 0) {\n // No progress made = circular dependency detected\n const remaining = allProjects.filter((p) => !processed.has(p));\n\n // Try to identify the cycle\n const cycleInfo = findCycle(graph, remaining);\n\n throw new Error(\n `Circular dependency detected among: ${remaining.join(', ')}\\n` +\n (cycleInfo ? `Cycle: ${cycleInfo}\\n` : '') +\n 'Fix: Remove one of the dependencies to break the cycle.'\n );\n }\n\n // Sort alphabetically within layer for deterministic output\n currentLayer.sort();\n layers.push(currentLayer);\n\n // Mark as processed\n currentLayer.forEach((p) => processed.add(p));\n }\n\n return layers;\n}\n\n/**\n * Try to find and describe a cycle in the graph\n */\nfunction findCycle(graph: Record<string, string[]>, remaining: string[]): string | null {\n const visited = new Set<string>();\n const path: string[] = [];\n\n function dfs(node: string): string | null {\n if (path.includes(node)) {\n const cycleStart = path.indexOf(node);\n return [...path.slice(cycleStart), node].join(' -> ');\n }\n if (visited.has(node)) return null;\n\n visited.add(node);\n path.push(node);\n\n const deps = graph[node] || [];\n for (const dep of deps) {\n if (remaining.includes(dep)) {\n const result = dfs(dep);\n if (result) return result;\n }\n }\n\n path.pop();\n return null;\n }\n\n for (const node of remaining) {\n const cycle = dfs(node);\n if (cycle) return cycle;\n }\n\n return null;\n}\n\n/**\n * Sort graph in topological order with alphabetical sorting within layers\n * Returns enhanced format with level metadata\n *\n * @param graph - Unsorted dependency graph { project: [deps] }\n * @returns Sorted graph with level metadata { project: { level: number, dependsOn: [deps] } }\n */\nexport function sortGraphTopologically(graph: Record<string, string[]>): EnhancedGraph {\n const layers = computeTopologicalLayers(graph);\n const result: EnhancedGraph = {};\n\n // Add projects layer by layer (dependencies before dependents)\n layers.forEach((layer, levelIndex) => {\n for (const project of layer) {\n // Already sorted alphabetically within layer\n result[project] = {\n level: levelIndex,\n dependsOn: (graph[project] || []).sort(),\n };\n }\n });\n\n return result;\n}\n"]}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Graph Visualizer
3
+ *
4
+ * Generates visual representations of the architecture graph:
5
+ * - DOT format (for Graphviz)
6
+ * - Interactive HTML (using viz.js)
7
+ *
8
+ * Output files go to tmp/webpieces/ for easy viewing without committing.
9
+ */
10
+ import type { EnhancedGraph } from './graph-sorter';
11
+ /**
12
+ * Generate Graphviz DOT format from the graph
13
+ */
14
+ export declare function generateDot(graph: EnhancedGraph, title?: string): string;
15
+ /**
16
+ * Generate interactive HTML with embedded SVG using viz.js
17
+ */
18
+ export declare function generateHTML(dot: string, title?: string): string;
19
+ interface VisualizationPaths {
20
+ dotPath: string;
21
+ htmlPath: string;
22
+ }
23
+ /**
24
+ * Write visualization files to tmp/webpieces/
25
+ */
26
+ export declare function writeVisualization(graph: EnhancedGraph, workspaceRoot: string, title?: string): VisualizationPaths;
27
+ /**
28
+ * Open the HTML visualization in the default browser
29
+ */
30
+ export declare function openVisualization(htmlPath: string): boolean;
31
+ export {};
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Graph Visualizer
3
4
  *
@@ -7,57 +8,54 @@
7
8
  *
8
9
  * Output files go to tmp/webpieces/ for easy viewing without committing.
9
10
  */
10
-
11
- import * as fs from 'fs';
12
- import * as path from 'path';
13
- import { execSync } from 'child_process';
14
- import type { EnhancedGraph } from './graph-sorter';
15
- import { toError } from '../toError';
16
-
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.generateDot = generateDot;
13
+ exports.generateHTML = generateHTML;
14
+ exports.writeVisualization = writeVisualization;
15
+ exports.openVisualization = openVisualization;
16
+ const tslib_1 = require("tslib");
17
+ const fs = tslib_1.__importStar(require("fs"));
18
+ const path = tslib_1.__importStar(require("path"));
19
+ const child_process_1 = require("child_process");
17
20
  /**
18
21
  * Level colors for visualization
19
22
  */
20
- const LEVEL_COLORS: Record<number, string> = {
23
+ const LEVEL_COLORS = {
21
24
  0: '#E8F5E9', // Light green - foundation
22
25
  1: '#E3F2FD', // Light blue - middleware
23
26
  2: '#FFF3E0', // Light orange - applications
24
27
  3: '#FCE4EC', // Light pink - higher level
25
28
  };
26
-
27
29
  /**
28
30
  * Remove scope from name for display
29
31
  * '@scope/name' → 'name'
30
32
  * 'name' → 'name'
31
33
  */
32
- function getShortName(name: string): string {
33
- return name.includes('/') ? name.split('/').pop()! : name;
34
+ function getShortName(name) {
35
+ return name.includes('/') ? name.split('/').pop() : name;
34
36
  }
35
-
36
37
  /**
37
38
  * Generate Graphviz DOT format from the graph
38
39
  */
39
- export function generateDot(graph: EnhancedGraph, title: string = 'WebPieces Architecture'): string {
40
+ function generateDot(graph, title = 'WebPieces Architecture') {
40
41
  let dot = 'digraph Architecture {\n';
41
42
  dot += ' rankdir=TB;\n';
42
43
  dot += ' node [shape=box, style=filled, fontname="Arial"];\n';
43
44
  dot += ' edge [fontname="Arial"];\n\n';
44
-
45
45
  // Group projects by level
46
- const levels: Record<number, string[]> = {};
46
+ const levels = {};
47
47
  for (const [project, info] of Object.entries(graph)) {
48
- if (!levels[info.level]) levels[info.level] = [];
48
+ if (!levels[info.level])
49
+ levels[info.level] = [];
49
50
  levels[info.level].push(project);
50
51
  }
51
-
52
52
  // Create nodes with level-based colors
53
53
  for (const [project, info] of Object.entries(graph)) {
54
54
  const shortName = getShortName(project);
55
55
  const color = LEVEL_COLORS[info.level] || '#F5F5F5';
56
56
  dot += ` "${shortName}" [fillcolor="${color}", label="${shortName}\\n(L${info.level})"];\n`;
57
57
  }
58
-
59
58
  dot += '\n';
60
-
61
59
  // Create same-rank subgraphs for each level
62
60
  for (const [level, projects] of Object.entries(levels)) {
63
61
  dot += ` { rank=same; `;
@@ -67,9 +65,7 @@ export function generateDot(graph: EnhancedGraph, title: string = 'WebPieces Arc
67
65
  });
68
66
  dot += '}\n';
69
67
  }
70
-
71
68
  dot += '\n';
72
-
73
69
  // Create edges (dependencies)
74
70
  for (const [project, info] of Object.entries(graph)) {
75
71
  const shortName = getShortName(project);
@@ -78,23 +74,19 @@ export function generateDot(graph: EnhancedGraph, title: string = 'WebPieces Arc
78
74
  dot += ` "${shortName}" -> "${depShortName}";\n`;
79
75
  }
80
76
  }
81
-
82
77
  dot += '\n labelloc="t";\n';
83
78
  dot += ` label="${title}\\n(from architecture/dependencies.json)";\n`;
84
79
  dot += ' fontsize=20;\n';
85
80
  dot += '}\n';
86
-
87
81
  return dot;
88
82
  }
89
-
90
83
  /**
91
84
  * Generate interactive HTML with embedded SVG using viz.js
92
85
  */
93
- export function generateHTML(dot: string, title: string = 'WebPieces Architecture'): string {
86
+ function generateHTML(dot, title = 'WebPieces Architecture') {
94
87
  const styles = generateHTMLStyles();
95
88
  const legend = generateHTMLLegend();
96
89
  const script = generateHTMLScript(dot);
97
-
98
90
  return `<!DOCTYPE html>
99
91
  <html>
100
92
  <head>
@@ -111,8 +103,7 @@ export function generateHTML(dot: string, title: string = 'WebPieces Architectur
111
103
  </body>
112
104
  </html>`;
113
105
  }
114
-
115
- function generateHTMLStyles(): string {
106
+ function generateHTMLStyles() {
116
107
  return `
117
108
  body {
118
109
  margin: 0;
@@ -155,8 +146,7 @@ function generateHTMLStyles(): string {
155
146
  }
156
147
  `;
157
148
  }
158
-
159
- function generateHTMLLegend(): string {
149
+ function generateHTMLLegend() {
160
150
  return `<div class="legend">
161
151
  <h2>Legend</h2>
162
152
  <div class="legend-item">
@@ -176,8 +166,7 @@ function generateHTMLLegend(): string {
176
166
  </div>
177
167
  </div>`;
178
168
  }
179
-
180
- function generateHTMLScript(dot: string): string {
169
+ function generateHTMLScript(dot) {
181
170
  return `
182
171
  const dot = ${JSON.stringify(dot)};
183
172
  const viz = new Viz();
@@ -192,62 +181,49 @@ function generateHTMLScript(dot: string): string {
192
181
  });
193
182
  `;
194
183
  }
195
-
196
- interface VisualizationPaths {
197
- dotPath: string;
198
- htmlPath: string;
199
- }
200
-
201
184
  /**
202
185
  * Write visualization files to tmp/webpieces/
203
186
  */
204
- export function writeVisualization(
205
- graph: EnhancedGraph,
206
- workspaceRoot: string,
207
- title: string = 'WebPieces Architecture'
208
- ): VisualizationPaths {
187
+ function writeVisualization(graph, workspaceRoot, title = 'WebPieces Architecture') {
209
188
  const outputDir = path.join(workspaceRoot, 'tmp', 'webpieces');
210
-
211
189
  // Ensure directory exists
212
190
  if (!fs.existsSync(outputDir)) {
213
191
  fs.mkdirSync(outputDir, { recursive: true });
214
192
  }
215
-
216
193
  // Generate DOT
217
194
  const dot = generateDot(graph, title);
218
195
  const dotPath = path.join(outputDir, 'architecture.dot');
219
196
  fs.writeFileSync(dotPath, dot, 'utf-8');
220
-
221
197
  // Generate HTML
222
198
  const html = generateHTML(dot, title);
223
199
  const htmlPath = path.join(outputDir, 'architecture.html');
224
200
  fs.writeFileSync(htmlPath, html, 'utf-8');
225
-
226
201
  return { dotPath, htmlPath };
227
202
  }
228
-
229
203
  /**
230
204
  * Open the HTML visualization in the default browser
231
205
  */
232
- export function openVisualization(htmlPath: string): boolean {
206
+ function openVisualization(htmlPath) {
233
207
  // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
234
208
  try {
235
209
  const platform = process.platform;
236
- let openCommand: string;
237
-
210
+ let openCommand;
238
211
  if (platform === 'darwin') {
239
212
  openCommand = `open "${htmlPath}"`;
240
- } else if (platform === 'win32') {
213
+ }
214
+ else if (platform === 'win32') {
241
215
  openCommand = `start "" "${htmlPath}"`;
242
- } else {
216
+ }
217
+ else {
243
218
  openCommand = `xdg-open "${htmlPath}"`;
244
219
  }
245
-
246
- execSync(openCommand, { stdio: 'ignore' });
220
+ (0, child_process_1.execSync)(openCommand, { stdio: 'ignore' });
247
221
  return true;
248
- } catch (err: unknown) {
222
+ }
223
+ catch (err) {
249
224
  //const error = toError(err);
250
225
  void err;
251
226
  return false;
252
227
  }
253
228
  }
229
+ //# sourceMappingURL=graph-visualizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-visualizer.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-visualizer.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;AA8BH,kCAiDC;AAKD,oCAoBC;AA2FD,gDAuBC;AAKD,8CAqBC;;AAlPD,+CAAyB;AACzB,mDAA6B;AAC7B,iDAAyC;AAIzC;;GAEG;AACH,MAAM,YAAY,GAA2B;IACzC,CAAC,EAAE,SAAS,EAAE,2BAA2B;IACzC,CAAC,EAAE,SAAS,EAAE,0BAA0B;IACxC,CAAC,EAAE,SAAS,EAAE,8BAA8B;IAC5C,CAAC,EAAE,SAAS,EAAE,4BAA4B;CAC7C,CAAC;AAEF;;;;GAIG;AACH,SAAS,YAAY,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CAAC,KAAoB,EAAE,QAAgB,wBAAwB;IACtF,IAAI,GAAG,GAAG,0BAA0B,CAAC;IACrC,GAAG,IAAI,iBAAiB,CAAC;IACzB,GAAG,IAAI,uDAAuD,CAAC;IAC/D,GAAG,IAAI,gCAAgC,CAAC;IAExC,0BAA0B;IAC1B,MAAM,MAAM,GAA6B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,uCAAuC;IACvC,KAAK,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC;QACpD,GAAG,IAAI,MAAM,SAAS,iBAAiB,KAAK,aAAa,SAAS,QAAQ,IAAI,CAAC,KAAK,QAAQ,CAAC;IACjG,CAAC;IAED,GAAG,IAAI,IAAI,CAAC;IAEZ,4CAA4C;IAC5C,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACrD,GAAG,IAAI,iBAAiB,CAAC;QACzB,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YACnB,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;YAClC,GAAG,IAAI,IAAI,SAAS,KAAK,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,GAAG,IAAI,KAAK,CAAC;IACjB,CAAC;IAED,GAAG,IAAI,IAAI,CAAC;IAEZ,8BAA8B;IAC9B,KAAK,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;YACrC,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;YACvC,GAAG,IAAI,MAAM,SAAS,SAAS,YAAY,MAAM,CAAC;QACtD,CAAC;IACL,CAAC;IAED,GAAG,IAAI,qBAAqB,CAAC;IAC7B,GAAG,IAAI,YAAY,KAAK,8CAA8C,CAAC;IACvE,GAAG,IAAI,kBAAkB,CAAC;IAC1B,GAAG,IAAI,KAAK,CAAC;IAEb,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,GAAW,EAAE,QAAgB,wBAAwB;IAC9E,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAEvC,OAAO;;;aAGE,KAAK;;;aAGL,MAAM;;;UAGT,KAAK;MACT,MAAM;;cAEE,MAAM;;QAEZ,CAAC;AACT,CAAC;AAED,SAAS,kBAAkB;IACvB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAwCN,CAAC;AACN,CAAC;AAED,SAAS,kBAAkB;IACvB,OAAO;;;;;;;;;;;;;;;;;WAiBA,CAAC;AACZ,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAW;IACnC,OAAO;sBACW,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;;;;;;;;;;;KAWpC,CAAC;AACN,CAAC;AAOD;;GAEG;AACH,SAAgB,kBAAkB,CAC9B,KAAoB,EACpB,aAAqB,EACrB,QAAgB,wBAAwB;IAExC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;IAE/D,0BAA0B;IAC1B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,eAAe;IACf,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;IACzD,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IAExC,gBAAgB;IAChB,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IAC3D,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAE1C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,QAAgB;IAC9C,8DAA8D;IAC9D,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,WAAmB,CAAC;QAExB,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACxB,WAAW,GAAG,SAAS,QAAQ,GAAG,CAAC;QACvC,CAAC;aAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;YAC9B,WAAW,GAAG,aAAa,QAAQ,GAAG,CAAC;QAC3C,CAAC;aAAM,CAAC;YACJ,WAAW,GAAG,aAAa,QAAQ,GAAG,CAAC;QAC3C,CAAC;QAED,IAAA,wBAAQ,EAAC,WAAW,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACpB,6BAA6B;QAC7B,KAAK,GAAG,CAAC;QACT,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC","sourcesContent":["/**\n * Graph Visualizer\n *\n * Generates visual representations of the architecture graph:\n * - DOT format (for Graphviz)\n * - Interactive HTML (using viz.js)\n *\n * Output files go to tmp/webpieces/ for easy viewing without committing.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { execSync } from 'child_process';\nimport type { EnhancedGraph } from './graph-sorter';\nimport { toError } from '../toError';\n\n/**\n * Level colors for visualization\n */\nconst LEVEL_COLORS: Record<number, string> = {\n 0: '#E8F5E9', // Light green - foundation\n 1: '#E3F2FD', // Light blue - middleware\n 2: '#FFF3E0', // Light orange - applications\n 3: '#FCE4EC', // Light pink - higher level\n};\n\n/**\n * Remove scope from name for display\n * '@scope/name' → 'name'\n * 'name' → 'name'\n */\nfunction getShortName(name: string): string {\n return name.includes('/') ? name.split('/').pop()! : name;\n}\n\n/**\n * Generate Graphviz DOT format from the graph\n */\nexport function generateDot(graph: EnhancedGraph, title: string = 'WebPieces Architecture'): string {\n let dot = 'digraph Architecture {\\n';\n dot += ' rankdir=TB;\\n';\n dot += ' node [shape=box, style=filled, fontname=\"Arial\"];\\n';\n dot += ' edge [fontname=\"Arial\"];\\n\\n';\n\n // Group projects by level\n const levels: Record<number, string[]> = {};\n for (const [project, info] of Object.entries(graph)) {\n if (!levels[info.level]) levels[info.level] = [];\n levels[info.level].push(project);\n }\n\n // Create nodes with level-based colors\n for (const [project, info] of Object.entries(graph)) {\n const shortName = getShortName(project);\n const color = LEVEL_COLORS[info.level] || '#F5F5F5';\n dot += ` \"${shortName}\" [fillcolor=\"${color}\", label=\"${shortName}\\\\n(L${info.level})\"];\\n`;\n }\n\n dot += '\\n';\n\n // Create same-rank subgraphs for each level\n for (const [level, projects] of Object.entries(levels)) {\n dot += ` { rank=same; `;\n projects.forEach((p) => {\n const shortName = getShortName(p);\n dot += `\"${shortName}\"; `;\n });\n dot += '}\\n';\n }\n\n dot += '\\n';\n\n // Create edges (dependencies)\n for (const [project, info] of Object.entries(graph)) {\n const shortName = getShortName(project);\n for (const dep of info.dependsOn || []) {\n const depShortName = getShortName(dep);\n dot += ` \"${shortName}\" -> \"${depShortName}\";\\n`;\n }\n }\n\n dot += '\\n labelloc=\"t\";\\n';\n dot += ` label=\"${title}\\\\n(from architecture/dependencies.json)\";\\n`;\n dot += ' fontsize=20;\\n';\n dot += '}\\n';\n\n return dot;\n}\n\n/**\n * Generate interactive HTML with embedded SVG using viz.js\n */\nexport function generateHTML(dot: string, title: string = 'WebPieces Architecture'): string {\n const styles = generateHTMLStyles();\n const legend = generateHTMLLegend();\n const script = generateHTMLScript(dot);\n\n return `<!DOCTYPE html>\n<html>\n<head>\n <title>${title}</title>\n <script src=\"https://cdn.jsdelivr.net/npm/viz.js@2.1.2/viz.js\"></script>\n <script src=\"https://cdn.jsdelivr.net/npm/viz.js@2.1.2/full.render.js\"></script>\n <style>${styles}</style>\n</head>\n<body>\n <h1>${title}</h1>\n ${legend}\n <div id=\"graph\"></div>\n <script>${script}</script>\n</body>\n</html>`;\n}\n\nfunction generateHTMLStyles(): string {\n return `\n body {\n margin: 0;\n padding: 20px;\n font-family: Arial, sans-serif;\n background: #f5f5f5;\n }\n h1 {\n text-align: center;\n color: #333;\n }\n #graph {\n text-align: center;\n background: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n }\n .legend {\n margin: 20px auto;\n max-width: 600px;\n padding: 15px;\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n }\n .legend h2 {\n margin-top: 0;\n }\n .legend-item {\n margin: 8px 0;\n }\n .legend-box {\n display: inline-block;\n width: 20px;\n height: 20px;\n border: 1px solid #ccc;\n margin-right: 10px;\n vertical-align: middle;\n }\n `;\n}\n\nfunction generateHTMLLegend(): string {\n return `<div class=\"legend\">\n <h2>Legend</h2>\n <div class=\"legend-item\">\n <span class=\"legend-box\" style=\"background: #E8F5E9;\"></span>\n <strong>Level 0:</strong> Foundation libraries (no dependencies)\n </div>\n <div class=\"legend-item\">\n <span class=\"legend-box\" style=\"background: #E3F2FD;\"></span>\n <strong>Level 1:</strong> Middleware libraries (depend on Level 0)\n </div>\n <div class=\"legend-item\">\n <span class=\"legend-box\" style=\"background: #FFF3E0;\"></span>\n <strong>Level 2:</strong> Applications (depend on Level 1)\n </div>\n <div class=\"legend-item\" style=\"margin-top: 15px;\">\n <em>Note: Transitive dependencies are allowed but not shown in the graph.</em>\n </div>\n </div>`;\n}\n\nfunction generateHTMLScript(dot: string): string {\n return `\n const dot = ${JSON.stringify(dot)};\n const viz = new Viz();\n\n viz.renderSVGElement(dot)\n .then(element => {\n document.getElementById('graph').appendChild(element);\n })\n .catch(err => {\n console.error(err);\n document.getElementById('graph').innerHTML = '<pre>' + err + '</pre>';\n });\n `;\n}\n\ninterface VisualizationPaths {\n dotPath: string;\n htmlPath: string;\n}\n\n/**\n * Write visualization files to tmp/webpieces/\n */\nexport function writeVisualization(\n graph: EnhancedGraph,\n workspaceRoot: string,\n title: string = 'WebPieces Architecture'\n): VisualizationPaths {\n const outputDir = path.join(workspaceRoot, 'tmp', 'webpieces');\n\n // Ensure directory exists\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n // Generate DOT\n const dot = generateDot(graph, title);\n const dotPath = path.join(outputDir, 'architecture.dot');\n fs.writeFileSync(dotPath, dot, 'utf-8');\n\n // Generate HTML\n const html = generateHTML(dot, title);\n const htmlPath = path.join(outputDir, 'architecture.html');\n fs.writeFileSync(htmlPath, html, 'utf-8');\n\n return { dotPath, htmlPath };\n}\n\n/**\n * Open the HTML visualization in the default browser\n */\nexport function openVisualization(htmlPath: string): boolean {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const platform = process.platform;\n let openCommand: string;\n\n if (platform === 'darwin') {\n openCommand = `open \"${htmlPath}\"`;\n } else if (platform === 'win32') {\n openCommand = `start \"\" \"${htmlPath}\"`;\n } else {\n openCommand = `xdg-open \"${htmlPath}\"`;\n }\n\n execSync(openCommand, { stdio: 'ignore' });\n return true;\n } catch (err: unknown) {\n //const error = toError(err);\n void err;\n return false;\n }\n}\n"]}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Package Validator
3
+ *
4
+ * Validates that package.json dependencies match the project.json build.dependsOn
5
+ * This ensures the two sources of truth don't drift apart.
6
+ */
7
+ /**
8
+ * Validation result for a single project
9
+ */
10
+ export interface ProjectValidationResult {
11
+ project: string;
12
+ valid: boolean;
13
+ missingInPackageJson: string[];
14
+ extraInPackageJson: string[];
15
+ }
16
+ /**
17
+ * Overall validation result
18
+ */
19
+ export interface ValidationResult {
20
+ valid: boolean;
21
+ errors: string[];
22
+ projectResults: ProjectValidationResult[];
23
+ }
24
+ /**
25
+ * Validate that package.json dependencies match the dependency graph
26
+ *
27
+ * For each project in the graph:
28
+ * - Check that all graph dependencies exist in package.json
29
+ * - Maps project names to package names for accurate comparison
30
+ *
31
+ * @param graph - Enhanced graph with project dependencies (uses project names)
32
+ * @param workspaceRoot - Absolute path to workspace root
33
+ * @returns Validation result with errors if any
34
+ */
35
+ interface GraphEntry {
36
+ level: number;
37
+ dependsOn: string[];
38
+ }
39
+ export declare function validatePackageJsonDependencies(graph: Record<string, GraphEntry>, workspaceRoot: string): Promise<ValidationResult>;
40
+ export {};