@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
  * Validate Versions Locked Executor
3
4
  *
@@ -13,72 +14,52 @@
13
14
  * Usage:
14
15
  * nx run architecture:validate-versions-locked
15
16
  */
16
-
17
- import type { ExecutorContext } from '@nx/devkit';
18
- import * as fs from 'fs';
19
- import * as path from 'path';
20
- import { toError } from '../../toError';
21
-
22
- export interface ValidateVersionsLockedOptions {
23
- // No options needed
24
- }
25
-
26
- export interface ExecutorResult {
27
- success: boolean;
28
- }
29
-
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.default = runExecutor;
19
+ const tslib_1 = require("tslib");
20
+ const fs = tslib_1.__importStar(require("fs"));
21
+ const path = tslib_1.__importStar(require("path"));
22
+ const toError_1 = require("../../toError");
30
23
  // webpieces-disable max-lines-new-methods -- Existing method from renamed validate-versions file
31
24
  // Find all package.json files except node_modules, dist, .nx, .angular
32
- function findPackageJsonFiles(dir: string, basePath = ''): string[] {
33
- const files: string[] = [];
25
+ function findPackageJsonFiles(dir, basePath = '') {
26
+ const files = [];
34
27
  const items = fs.readdirSync(dir);
35
-
36
28
  for (const item of items) {
37
29
  const fullPath = path.join(dir, item);
38
30
  const relativePath = path.join(basePath, item);
39
-
40
31
  // Skip these directories
41
- if (
42
- ['node_modules', 'dist', '.nx', '.angular', 'tmp', '.git'].includes(
43
- item,
44
- )
45
- ) {
32
+ if (['node_modules', 'dist', '.nx', '.angular', 'tmp', '.git'].includes(item)) {
46
33
  continue;
47
34
  }
48
-
49
35
  // Skip platform-specific node_modules backups (node_modules_mac, node_modules_linux, etc.)
50
36
  if (item.startsWith('node_modules_')) {
51
37
  continue;
52
38
  }
53
-
54
39
  // Skip all hidden directories (starting with .)
55
40
  if (item.startsWith('.')) {
56
41
  continue;
57
42
  }
58
-
59
43
  const stat = fs.statSync(fullPath);
60
44
  if (stat.isDirectory()) {
61
45
  files.push(...findPackageJsonFiles(fullPath, relativePath));
62
- } else if (item === 'package.json') {
46
+ }
47
+ else if (item === 'package.json') {
63
48
  files.push(fullPath);
64
49
  }
65
50
  }
66
-
67
51
  return files;
68
52
  }
69
-
70
53
  // Check if a version string uses semver ranges
71
- function hasSemverRange(version: string): boolean {
54
+ function hasSemverRange(version) {
72
55
  // Allow workspace protocol
73
56
  if (version.startsWith('workspace:')) {
74
57
  return false;
75
58
  }
76
-
77
59
  // Allow file: protocol (for local packages)
78
60
  if (version.startsWith('file:')) {
79
61
  return false;
80
62
  }
81
-
82
63
  // Check for common semver range patterns
83
64
  const semverPatterns = [
84
65
  /^\^/, // ^1.2.3
@@ -95,19 +76,16 @@ function hasSemverRange(version: string): boolean {
95
76
  /^latest$/, // latest
96
77
  /^next$/, // next
97
78
  ];
98
-
99
79
  return semverPatterns.some((pattern) => pattern.test(version));
100
80
  }
101
-
102
81
  // webpieces-disable max-lines-new-methods -- Existing method from renamed validate-versions file
103
82
  // Validate a single package.json file for semver ranges
104
- function validatePackageJson(filePath: string): string[] {
83
+ function validatePackageJson(filePath) {
105
84
  // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
106
85
  try {
107
86
  const content = fs.readFileSync(filePath, 'utf-8');
108
87
  const pkg = JSON.parse(content);
109
- const errors: string[] = [];
110
-
88
+ const errors = [];
111
89
  // Check dependencies
112
90
  if (pkg.dependencies) {
113
91
  for (const [name, version] of Object.entries(pkg.dependencies)) {
@@ -115,15 +93,11 @@ function validatePackageJson(filePath: string): string[] {
115
93
  if (name.startsWith('@webpieces/')) {
116
94
  continue;
117
95
  }
118
-
119
- if (hasSemverRange(version as string)) {
120
- errors.push(
121
- `dependencies.${name}: "${version}" uses semver range (must be locked to exact version)`,
122
- );
96
+ if (hasSemverRange(version)) {
97
+ errors.push(`dependencies.${name}: "${version}" uses semver range (must be locked to exact version)`);
123
98
  }
124
99
  }
125
100
  }
126
-
127
101
  // Check devDependencies
128
102
  if (pkg.devDependencies) {
129
103
  for (const [name, version] of Object.entries(pkg.devDependencies)) {
@@ -131,134 +105,108 @@ function validatePackageJson(filePath: string): string[] {
131
105
  if (name.startsWith('@webpieces/')) {
132
106
  continue;
133
107
  }
134
-
135
- if (hasSemverRange(version as string)) {
136
- errors.push(
137
- `devDependencies.${name}: "${version}" uses semver range (must be locked to exact version)`,
138
- );
108
+ if (hasSemverRange(version)) {
109
+ errors.push(`devDependencies.${name}: "${version}" uses semver range (must be locked to exact version)`);
139
110
  }
140
111
  }
141
112
  }
142
-
143
113
  // Check peerDependencies (these can have ranges for compatibility)
144
114
  // We don't validate peerDependencies for semver ranges since they're meant to be flexible
145
-
146
115
  return errors;
147
- } catch (err: unknown) {
148
- const error = toError(err);
116
+ }
117
+ catch (err) {
118
+ const error = (0, toError_1.toError)(err);
149
119
  return [`Failed to parse ${filePath}: ${error.message}`];
150
120
  }
151
121
  }
152
-
153
- // Track all dependency versions across the monorepo
154
- interface DependencyUsage {
155
- version: string;
156
- file: string;
157
- type: 'dependencies' | 'devDependencies';
158
- }
159
-
160
122
  // webpieces-disable max-lines-new-methods -- Collecting dependencies from all package.json files
161
123
  // Collect all dependency versions from all package.json files
162
- function collectAllDependencies(workspaceRoot: string): Map<string, DependencyUsage[]> {
163
- const dependencyMap = new Map<string, DependencyUsage[]>();
124
+ function collectAllDependencies(workspaceRoot) {
125
+ const dependencyMap = new Map();
164
126
  const packageFiles = findPackageJsonFiles(workspaceRoot);
165
-
166
127
  for (const filePath of packageFiles) {
167
128
  // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
168
129
  try {
169
130
  const content = fs.readFileSync(filePath, 'utf-8');
170
131
  const pkg = JSON.parse(content);
171
132
  const relativePath = path.relative(workspaceRoot, filePath);
172
-
173
133
  // Collect dependencies
174
134
  if (pkg.dependencies) {
175
135
  for (const [name, version] of Object.entries(pkg.dependencies)) {
176
136
  // Skip internal workspace packages
177
- if (name.startsWith('@webpieces/')) continue;
178
-
179
- const usage: DependencyUsage = {
180
- version: version as string,
137
+ if (name.startsWith('@webpieces/'))
138
+ continue;
139
+ const usage = {
140
+ version: version,
181
141
  file: relativePath,
182
142
  type: 'dependencies'
183
143
  };
184
-
185
144
  if (!dependencyMap.has(name)) {
186
145
  dependencyMap.set(name, []);
187
146
  }
188
- dependencyMap.get(name)!.push(usage);
147
+ dependencyMap.get(name).push(usage);
189
148
  }
190
149
  }
191
-
192
150
  // Collect devDependencies
193
151
  if (pkg.devDependencies) {
194
152
  for (const [name, version] of Object.entries(pkg.devDependencies)) {
195
153
  // Skip internal workspace packages
196
- if (name.startsWith('@webpieces/')) continue;
197
-
198
- const usage: DependencyUsage = {
199
- version: version as string,
154
+ if (name.startsWith('@webpieces/'))
155
+ continue;
156
+ const usage = {
157
+ version: version,
200
158
  file: relativePath,
201
159
  type: 'devDependencies'
202
160
  };
203
-
204
161
  if (!dependencyMap.has(name)) {
205
162
  dependencyMap.set(name, []);
206
163
  }
207
- dependencyMap.get(name)!.push(usage);
164
+ dependencyMap.get(name).push(usage);
208
165
  }
209
166
  }
210
- } catch (err: unknown) {
167
+ }
168
+ catch (err) {
211
169
  // const error = toError(err);
212
170
  // Intentionally skip files that can't be parsed - this is expected for some package.json files
213
171
  }
214
172
  }
215
-
216
173
  return dependencyMap;
217
174
  }
218
-
219
175
  // webpieces-disable max-lines-new-methods -- Simple iteration logic, splitting would reduce clarity
220
176
  // Check for version conflicts across package.json files
221
- function checkVersionConflicts(workspaceRoot: string): string[] {
177
+ function checkVersionConflicts(workspaceRoot) {
222
178
  console.log('\n🔍 Checking for version conflicts across package.json files:');
223
-
224
179
  const dependencyMap = collectAllDependencies(workspaceRoot);
225
- const conflicts: string[] = [];
226
-
180
+ const conflicts = [];
227
181
  for (const [packageName, usages] of dependencyMap.entries()) {
228
182
  // Get unique versions (ignoring workspace: and file: protocols)
229
- const versions = new Set(
230
- usages
231
- .map(u => u.version)
232
- .filter(v => !v.startsWith('workspace:') && !v.startsWith('file:'))
233
- );
234
-
183
+ const versions = new Set(usages
184
+ .map(u => u.version)
185
+ .filter(v => !v.startsWith('workspace:') && !v.startsWith('file:')));
235
186
  if (versions.size > 1) {
236
187
  const conflictDetails = usages
237
188
  .filter(u => !u.version.startsWith('workspace:') && !u.version.startsWith('file:'))
238
189
  .map(u => ` ${u.file} (${u.type}): ${u.version}`)
239
190
  .join('\n');
240
-
241
191
  conflicts.push(` ❌ ${packageName} has ${versions.size} different versions:\n${conflictDetails}`);
242
192
  }
243
193
  }
244
-
245
194
  if (conflicts.length === 0) {
246
195
  console.log(' ✅ No version conflicts found');
247
- } else {
196
+ }
197
+ else {
248
198
  for (const conflict of conflicts) {
249
199
  console.log(conflict);
250
200
  }
251
201
  }
252
-
253
202
  return conflicts;
254
203
  }
255
-
256
204
  /**
257
205
  * Prints the educational message explaining why semver ranges are forbidden.
258
206
  * This helps developers understand the rationale behind locked versions.
259
207
  */
260
208
  // webpieces-disable max-lines-new-methods -- Educational message template, splitting reduces clarity
261
- function printSemverRangeEducationalMessage(semverErrors: number): void {
209
+ function printSemverRangeEducationalMessage(semverErrors) {
262
210
  console.log(`
263
211
  ❌ SEMVER RANGES DETECTED - BUILD FAILED
264
212
 
@@ -308,61 +256,46 @@ This way, every library change is:
308
256
 
309
257
  `);
310
258
  }
311
-
312
- type SemverRangeResult = { errors: number };
313
-
314
259
  // Check semver ranges in all package.json files - FAILS if any found
315
- function checkSemverRanges(workspaceRoot: string): SemverRangeResult {
260
+ function checkSemverRanges(workspaceRoot) {
316
261
  console.log('\n📋 Checking for unlocked versions (semver ranges):');
317
262
  const packageFiles = findPackageJsonFiles(workspaceRoot);
318
263
  let semverErrors = 0;
319
-
320
264
  for (const filePath of packageFiles) {
321
265
  const relativePath = path.relative(workspaceRoot, filePath);
322
266
  const errors = validatePackageJson(filePath);
323
-
324
267
  if (errors.length > 0) {
325
268
  console.log(` ❌ ${relativePath}:`);
326
269
  for (const error of errors) {
327
270
  console.log(` ${error}`);
328
271
  }
329
272
  semverErrors += errors.length;
330
- } else {
273
+ }
274
+ else {
331
275
  console.log(` ✅ ${relativePath}`);
332
276
  }
333
277
  }
334
-
335
278
  return { errors: semverErrors };
336
279
  }
337
-
338
- export default async function runExecutor(
339
- _options: ValidateVersionsLockedOptions,
340
- context: ExecutorContext
341
- ): Promise<ExecutorResult> {
280
+ async function runExecutor(_options, context) {
342
281
  console.log('\n🔒 Validating Package Versions are LOCKED and CONSISTENT\n');
343
-
344
282
  const workspaceRoot = context.root;
345
-
346
283
  // Step 1: Check for semver ranges (FAILS if any found)
347
284
  const semverResult = checkSemverRanges(workspaceRoot);
348
285
  const semverErrors = semverResult.errors;
349
286
  const packageFiles = findPackageJsonFiles(workspaceRoot);
350
-
351
287
  // Step 2: Check for version conflicts across package.json files
352
288
  const versionConflicts = checkVersionConflicts(workspaceRoot);
353
-
354
289
  // Summary
355
290
  console.log(`\n📊 Summary:`);
356
291
  console.log(` Files checked: ${packageFiles.length}`);
357
292
  console.log(` Unlocked versions (semver ranges): ${semverErrors}`);
358
293
  console.log(` Version conflicts: ${versionConflicts.length}`);
359
-
360
294
  // Fail on semver ranges with educational message
361
295
  if (semverErrors > 0) {
362
296
  printSemverRangeEducationalMessage(semverErrors);
363
297
  return { success: false };
364
298
  }
365
-
366
299
  // Fail on version conflicts
367
300
  if (versionConflicts.length > 0) {
368
301
  console.log('\n❌ VALIDATION FAILED!');
@@ -370,7 +303,7 @@ export default async function runExecutor(
370
303
  console.log(' This prevents "works on my machine" bugs where different projects use different library versions.\n');
371
304
  return { success: false };
372
305
  }
373
-
374
306
  console.log('\n✅ VALIDATION PASSED! All versions are locked and consistent.');
375
307
  return { success: true };
376
308
  }
309
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-versions-locked/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Versions Locked Executor\n *\n * Validates that package.json versions are:\n * 1. LOCKED (exact versions, no semver ranges like ^, ~, *)\n * 2. CONSISTENT across all package.json files (no version conflicts)\n *\n * Why locked versions matter:\n * - Micro bugs ARE introduced via patch versions (1.4.5 → 1.4.6)\n * - git bisect fails when software changes OUTSIDE of git\n * - Library upgrades must be explicit via PR/commit, not implicit drift\n *\n * Usage:\n * nx run architecture:validate-versions-locked\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { toError } from '../../toError';\n\nexport interface ValidateVersionsLockedOptions {\n // No options needed\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\n// webpieces-disable max-lines-new-methods -- Existing method from renamed validate-versions file\n// Find all package.json files except node_modules, dist, .nx, .angular\nfunction findPackageJsonFiles(dir: string, basePath = ''): string[] {\n const files: string[] = [];\n const items = fs.readdirSync(dir);\n\n for (const item of items) {\n const fullPath = path.join(dir, item);\n const relativePath = path.join(basePath, item);\n\n // Skip these directories\n if (\n ['node_modules', 'dist', '.nx', '.angular', 'tmp', '.git'].includes(\n item,\n )\n ) {\n continue;\n }\n\n // Skip platform-specific node_modules backups (node_modules_mac, node_modules_linux, etc.)\n if (item.startsWith('node_modules_')) {\n continue;\n }\n\n // Skip all hidden directories (starting with .)\n if (item.startsWith('.')) {\n continue;\n }\n\n const stat = fs.statSync(fullPath);\n if (stat.isDirectory()) {\n files.push(...findPackageJsonFiles(fullPath, relativePath));\n } else if (item === 'package.json') {\n files.push(fullPath);\n }\n }\n\n return files;\n}\n\n// Check if a version string uses semver ranges\nfunction hasSemverRange(version: string): boolean {\n // Allow workspace protocol\n if (version.startsWith('workspace:')) {\n return false;\n }\n\n // Allow file: protocol (for local packages)\n if (version.startsWith('file:')) {\n return false;\n }\n\n // Check for common semver range patterns\n const semverPatterns = [\n /^\\^/, // ^1.2.3\n /^~/, // ~1.2.3\n /^\\+/, // +1.2.3\n /^\\*/, // *\n /^>/, // >1.2.3\n /^</, // <1.2.3\n /^>=/, // >=1.2.3\n /^<=/, // <=1.2.3\n /\\|\\|/, // 1.2.3 || 2.x\n / - /, // 1.2.3 - 2.3.4\n /^\\d+\\.x/, // 1.x, 1.2.x\n /^latest$/, // latest\n /^next$/, // next\n ];\n\n return semverPatterns.some((pattern) => pattern.test(version));\n}\n\n// webpieces-disable max-lines-new-methods -- Existing method from renamed validate-versions file\n// Validate a single package.json file for semver ranges\nfunction validatePackageJson(filePath: string): string[] {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const pkg = JSON.parse(content);\n const errors: string[] = [];\n\n // Check dependencies\n if (pkg.dependencies) {\n for (const [name, version] of Object.entries(pkg.dependencies)) {\n // Skip internal workspace packages\n if (name.startsWith('@webpieces/')) {\n continue;\n }\n\n if (hasSemverRange(version as string)) {\n errors.push(\n `dependencies.${name}: \"${version}\" uses semver range (must be locked to exact version)`,\n );\n }\n }\n }\n\n // Check devDependencies\n if (pkg.devDependencies) {\n for (const [name, version] of Object.entries(pkg.devDependencies)) {\n // Skip internal workspace packages\n if (name.startsWith('@webpieces/')) {\n continue;\n }\n\n if (hasSemverRange(version as string)) {\n errors.push(\n `devDependencies.${name}: \"${version}\" uses semver range (must be locked to exact version)`,\n );\n }\n }\n }\n\n // Check peerDependencies (these can have ranges for compatibility)\n // We don't validate peerDependencies for semver ranges since they're meant to be flexible\n\n return errors;\n } catch (err: unknown) {\n const error = toError(err);\n return [`Failed to parse ${filePath}: ${error.message}`];\n }\n}\n\n// Track all dependency versions across the monorepo\ninterface DependencyUsage {\n version: string;\n file: string;\n type: 'dependencies' | 'devDependencies';\n}\n\n// webpieces-disable max-lines-new-methods -- Collecting dependencies from all package.json files\n// Collect all dependency versions from all package.json files\nfunction collectAllDependencies(workspaceRoot: string): Map<string, DependencyUsage[]> {\n const dependencyMap = new Map<string, DependencyUsage[]>();\n const packageFiles = findPackageJsonFiles(workspaceRoot);\n\n for (const filePath of packageFiles) {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const pkg = JSON.parse(content);\n const relativePath = path.relative(workspaceRoot, filePath);\n\n // Collect dependencies\n if (pkg.dependencies) {\n for (const [name, version] of Object.entries(pkg.dependencies)) {\n // Skip internal workspace packages\n if (name.startsWith('@webpieces/')) continue;\n\n const usage: DependencyUsage = {\n version: version as string,\n file: relativePath,\n type: 'dependencies'\n };\n\n if (!dependencyMap.has(name)) {\n dependencyMap.set(name, []);\n }\n dependencyMap.get(name)!.push(usage);\n }\n }\n\n // Collect devDependencies\n if (pkg.devDependencies) {\n for (const [name, version] of Object.entries(pkg.devDependencies)) {\n // Skip internal workspace packages\n if (name.startsWith('@webpieces/')) continue;\n\n const usage: DependencyUsage = {\n version: version as string,\n file: relativePath,\n type: 'devDependencies'\n };\n\n if (!dependencyMap.has(name)) {\n dependencyMap.set(name, []);\n }\n dependencyMap.get(name)!.push(usage);\n }\n }\n } catch (err: unknown) {\n // const error = toError(err);\n // Intentionally skip files that can't be parsed - this is expected for some package.json files\n }\n }\n\n return dependencyMap;\n}\n\n// webpieces-disable max-lines-new-methods -- Simple iteration logic, splitting would reduce clarity\n// Check for version conflicts across package.json files\nfunction checkVersionConflicts(workspaceRoot: string): string[] {\n console.log('\\n🔍 Checking for version conflicts across package.json files:');\n\n const dependencyMap = collectAllDependencies(workspaceRoot);\n const conflicts: string[] = [];\n\n for (const [packageName, usages] of dependencyMap.entries()) {\n // Get unique versions (ignoring workspace: and file: protocols)\n const versions = new Set(\n usages\n .map(u => u.version)\n .filter(v => !v.startsWith('workspace:') && !v.startsWith('file:'))\n );\n\n if (versions.size > 1) {\n const conflictDetails = usages\n .filter(u => !u.version.startsWith('workspace:') && !u.version.startsWith('file:'))\n .map(u => ` ${u.file} (${u.type}): ${u.version}`)\n .join('\\n');\n\n conflicts.push(` ❌ ${packageName} has ${versions.size} different versions:\\n${conflictDetails}`);\n }\n }\n\n if (conflicts.length === 0) {\n console.log(' ✅ No version conflicts found');\n } else {\n for (const conflict of conflicts) {\n console.log(conflict);\n }\n }\n\n return conflicts;\n}\n\n/**\n * Prints the educational message explaining why semver ranges are forbidden.\n * This helps developers understand the rationale behind locked versions.\n */\n// webpieces-disable max-lines-new-methods -- Educational message template, splitting reduces clarity\nfunction printSemverRangeEducationalMessage(semverErrors: number): void {\n console.log(`\n❌ SEMVER RANGES DETECTED - BUILD FAILED\n\nFound ${semverErrors} package(s) using semver ranges (^, ~, *, etc.) instead of locked versions.\n\nWHY THIS IS A HARD FAILURE:\n═══════════════════════════════════════════════════════════════════════════════\n\n1. MICRO BUGS ARE REAL\n Thinking that patch versions (1.4.5 → 1.4.6) don't introduce bugs is wrong.\n They do. Sometimes what looks like an \"easy fix\" breaks things in subtle ways.\n\n2. GIT BISECT BECOMES USELESS\n When you run \"git bisect\" to find when a bug was introduced, it fails if\n software changed OUTSIDE of git. You checkout an old commit, but node_modules\n has different versions than when that commit was made. The bug persists even\n in \"known good\" commits because the library versions drifted.\n\n3. THE \"MAGIC BUG\" PROBLEM\n You checkout code from 6 months ago to debug an issue. The bug is still there!\n But it wasn't there 6 months ago... The culprit: a minor version upgrade that\n happened silently without any PR or git commit. Impossible to track down.\n\n4. CHANGES OUTSIDE GIT = BAD\n Every change to your software should be tracked in version control.\n Implicit library upgrades via semver ranges violate this principle.\n\nTHE SOLUTION:\n═══════════════════════════════════════════════════════════════════════════════\n\nUse LOCKED (exact) versions for all dependencies:\n ❌ \"lodash\": \"^4.17.21\" <- BAD: allows 4.17.22, 4.18.0, etc.\n ❌ \"lodash\": \"~4.17.21\" <- BAD: allows 4.17.22, 4.17.23, etc.\n ✅ \"lodash\": \"4.17.21\" <- GOOD: locked to this exact version\n\nTo upgrade libraries, use an explicit process:\n 1. Run: npm update <package-name>\n 2. Test thoroughly\n 3. Commit the package.json AND package-lock.json changes\n 4. Create a PR so the upgrade is reviewed and tracked in git history\n\nThis way, every library change is:\n • Intentional (not accidental)\n • Reviewed (via PR)\n • Tracked (in git history)\n • Bisectable (git bisect works correctly)\n\n`);\n}\n\ntype SemverRangeResult = { errors: number };\n\n// Check semver ranges in all package.json files - FAILS if any found\nfunction checkSemverRanges(workspaceRoot: string): SemverRangeResult {\n console.log('\\n📋 Checking for unlocked versions (semver ranges):');\n const packageFiles = findPackageJsonFiles(workspaceRoot);\n let semverErrors = 0;\n\n for (const filePath of packageFiles) {\n const relativePath = path.relative(workspaceRoot, filePath);\n const errors = validatePackageJson(filePath);\n\n if (errors.length > 0) {\n console.log(` ❌ ${relativePath}:`);\n for (const error of errors) {\n console.log(` ${error}`);\n }\n semverErrors += errors.length;\n } else {\n console.log(` ✅ ${relativePath}`);\n }\n }\n\n return { errors: semverErrors };\n}\n\nexport default async function runExecutor(\n _options: ValidateVersionsLockedOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n console.log('\\n🔒 Validating Package Versions are LOCKED and CONSISTENT\\n');\n\n const workspaceRoot = context.root;\n\n // Step 1: Check for semver ranges (FAILS if any found)\n const semverResult = checkSemverRanges(workspaceRoot);\n const semverErrors = semverResult.errors;\n const packageFiles = findPackageJsonFiles(workspaceRoot);\n\n // Step 2: Check for version conflicts across package.json files\n const versionConflicts = checkVersionConflicts(workspaceRoot);\n\n // Summary\n console.log(`\\n📊 Summary:`);\n console.log(` Files checked: ${packageFiles.length}`);\n console.log(` Unlocked versions (semver ranges): ${semverErrors}`);\n console.log(` Version conflicts: ${versionConflicts.length}`);\n\n // Fail on semver ranges with educational message\n if (semverErrors > 0) {\n printSemverRangeEducationalMessage(semverErrors);\n return { success: false };\n }\n\n // Fail on version conflicts\n if (versionConflicts.length > 0) {\n console.log('\\n❌ VALIDATION FAILED!');\n console.log(' Fix version conflicts - all package.json files must use the same version for each dependency.');\n console.log(' This prevents \"works on my machine\" bugs where different projects use different library versions.\\n');\n return { success: false };\n }\n\n console.log('\\n✅ VALIDATION PASSED! All versions are locked and consistent.');\n return { success: true };\n}\n"]}
@@ -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>;
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Visualize Executor
3
4
  *
@@ -7,59 +8,44 @@
7
8
  * Usage:
8
9
  * nx run architecture:visualize
9
10
  */
10
-
11
- import type { ExecutorContext } from '@nx/devkit';
12
- import { loadBlessedGraph } from '../../lib/graph-loader';
13
- import { writeVisualization, openVisualization } from '../../lib/graph-visualizer';
14
- import { toError } from '../../toError';
15
-
16
- export interface VisualizeExecutorOptions {
17
- graphPath?: string;
18
- }
19
-
20
- export interface ExecutorResult {
21
- success: boolean;
22
- }
23
-
24
- export default async function runExecutor(
25
- options: VisualizeExecutorOptions,
26
- context: ExecutorContext
27
- ): Promise<ExecutorResult> {
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
+ const toError_1 = require("../../toError");
16
+ async function runExecutor(options, context) {
28
17
  const graphPath = options.graphPath;
29
18
  const workspaceRoot = context.root;
30
-
31
19
  console.log('\n🎨 Architecture Visualization\n');
32
-
33
20
  // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
34
21
  try {
35
22
  // Load the saved graph
36
23
  console.log('📂 Loading saved graph...');
37
- const graph = loadBlessedGraph(workspaceRoot, graphPath);
38
-
24
+ const graph = (0, graph_loader_1.loadBlessedGraph)(workspaceRoot, graphPath);
39
25
  if (!graph) {
40
26
  console.error('❌ No saved graph found at architecture/dependencies.json');
41
27
  console.error(' Run: nx run architecture:generate first');
42
28
  return { success: false };
43
29
  }
44
-
45
30
  // Generate visualization
46
31
  console.log('🎨 Generating visualization...');
47
- const vizPaths = writeVisualization(graph, workspaceRoot);
32
+ const vizPaths = (0, graph_visualizer_1.writeVisualization)(graph, workspaceRoot);
48
33
  console.log(`✅ Generated: ${vizPaths.dotPath}`);
49
34
  console.log(`✅ Generated: ${vizPaths.htmlPath}`);
50
-
51
35
  // Try to open in browser
52
36
  console.log('\n🌐 Opening visualization in browser...');
53
- if (openVisualization(vizPaths.htmlPath)) {
37
+ if ((0, graph_visualizer_1.openVisualization)(vizPaths.htmlPath)) {
54
38
  console.log('✅ Browser opened');
55
- } else {
39
+ }
40
+ else {
56
41
  console.log(`⚠️ Could not auto-open. Open manually: ${vizPaths.htmlPath}`);
57
42
  }
58
-
59
43
  return { success: true };
60
- } catch (err: unknown) {
61
- const error = toError(err);
44
+ }
45
+ catch (err) {
46
+ const error = (0, toError_1.toError)(err);
62
47
  console.error('❌ Visualization failed:', error.message);
63
48
  return { success: false };
64
49
  }
65
50
  }
51
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/visualize/executor.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;AAeH,8BAyCC;AArDD,yDAA0D;AAC1D,iEAAmF;AACnF,2CAAwC;AAUzB,KAAK,UAAU,WAAW,CACrC,OAAiC,EACjC,OAAwB;IAExB,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACpC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAEnC,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IAEjD,8DAA8D;IAC9D,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,QAAQ,GAAG,IAAA,qCAAkB,EAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEjD,yBAAyB;QACzB,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACxD,IAAI,IAAA,oCAAiB,EAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,GAAG,CAAC,2CAA2C,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;QAChF,CAAC;QAED,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,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';\nimport { toError } from '../../toError';\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.graphPath;\n const workspaceRoot = context.root;\n\n console.log('\\n🎨 Architecture Visualization\\n');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\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 vizPaths = writeVisualization(graph, workspaceRoot);\n console.log(`✅ Generated: ${vizPaths.dotPath}`);\n console.log(`✅ Generated: ${vizPaths.htmlPath}`);\n\n // Try to open in browser\n console.log('\\n🌐 Opening visualization in browser...');\n if (openVisualization(vizPaths.htmlPath)) {\n console.log('✅ Browser opened');\n } else {\n console.log(`⚠️ Could not auto-open. Open manually: ${vizPaths.htmlPath}`);\n }\n\n return { success: true };\n } catch (err: unknown) {\n const error = toError(err);\n console.error('❌ Visualization failed:', error.message);\n return { success: false };\n }\n}\n"]}
@@ -6,4 +6,8 @@ export * from './lib/graph-loader';
6
6
  export * from './lib/graph-visualizer';
7
7
  import { createNodesV2 } from './plugin';
8
8
  export { createNodesV2 };
9
- export default { name: '@webpieces/nx-webpieces-rules', createNodesV2 };
9
+ declare const _default: {
10
+ name: string;
11
+ createNodesV2: import("@nx/devkit").CreateNodesV2<import("./plugin").ArchitecturePluginOptions>;
12
+ };
13
+ export default _default;
package/src/index.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createNodesV2 = void 0;
4
+ const tslib_1 = require("tslib");
5
+ tslib_1.__exportStar(require("./lib/graph-generator"), exports);
6
+ tslib_1.__exportStar(require("./lib/graph-sorter"), exports);
7
+ tslib_1.__exportStar(require("./lib/graph-comparator"), exports);
8
+ tslib_1.__exportStar(require("./lib/package-validator"), exports);
9
+ tslib_1.__exportStar(require("./lib/graph-loader"), exports);
10
+ tslib_1.__exportStar(require("./lib/graph-visualizer"), exports);
11
+ const plugin_1 = require("./plugin");
12
+ Object.defineProperty(exports, "createNodesV2", { enumerable: true, get: function () { return plugin_1.createNodesV2; } });
13
+ exports.default = { name: '@webpieces/nx-webpieces-rules', createNodesV2: plugin_1.createNodesV2 };
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/nx-webpieces-rules/src/index.ts"],"names":[],"mappings":";;;;AAAA,gEAAsC;AACtC,6DAAmC;AACnC,iEAAuC;AACvC,kEAAwC;AACxC,6DAAmC;AACnC,iEAAuC;AACvC,qCAAyC;AAChC,8FADA,sBAAa,OACA;AACtB,kBAAe,EAAE,IAAI,EAAE,+BAA+B,EAAE,aAAa,EAAb,sBAAa,EAAE,CAAC","sourcesContent":["export * from './lib/graph-generator';\nexport * from './lib/graph-sorter';\nexport * from './lib/graph-comparator';\nexport * from './lib/package-validator';\nexport * from './lib/graph-loader';\nexport * from './lib/graph-visualizer';\nimport { createNodesV2 } from './plugin';\nexport { createNodesV2 };\nexport default { name: '@webpieces/nx-webpieces-rules', createNodesV2 };\n"]}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Graph Comparator
3
+ *
4
+ * Compares the current generated graph with the saved (blessed) graph.
5
+ * Used in validate mode to ensure developers have updated the graph file.
6
+ */
7
+ import type { EnhancedGraph } from './graph-sorter';
8
+ /**
9
+ * Difference between two graphs
10
+ */
11
+ export interface GraphDiff {
12
+ added: string[];
13
+ removed: string[];
14
+ modified: {
15
+ project: string;
16
+ addedDeps: string[];
17
+ removedDeps: string[];
18
+ levelChanged: {
19
+ from: number;
20
+ to: number;
21
+ } | null;
22
+ }[];
23
+ }
24
+ /**
25
+ * Comparison result
26
+ */
27
+ export interface ComparisonResult {
28
+ identical: boolean;
29
+ diff: GraphDiff;
30
+ summary: string;
31
+ }
32
+ /**
33
+ * Compare two graphs and return the differences
34
+ *
35
+ * @param current - Currently generated graph
36
+ * @param saved - Previously saved (blessed) graph
37
+ * @returns Comparison result with detailed diff
38
+ */
39
+ export declare function compareGraphs(current: EnhancedGraph, saved: EnhancedGraph): ComparisonResult;