@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
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = runExecutor;
4
+ const code_rules_1 = require("@webpieces/code-rules");
5
+ async function runExecutor(
6
+ // webpieces-disable no-any-unknown -- options are passed through to code-rules validators
7
+ options, context) {
8
+ return (0, code_rules_1.validatePrismaConverters)(options, context.root);
9
+ }
10
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-prisma-converters/executor.ts"],"names":[],"mappings":";;AAIA,8BAMC;AARD,sDAAiE;AAElD,KAAK,UAAU,WAAW;AACrC,0FAA0F;AAC1F,OAAgC,EAChC,OAAwB;IAExB,OAAO,IAAA,qCAAwB,EAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;AAC3D,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { validatePrismaConverters } from '@webpieces/code-rules';\n\nexport default async function runExecutor(\n // webpieces-disable no-any-unknown -- options are passed through to code-rules validators\n options: Record<string, unknown>,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return validatePrismaConverters(options, context.root);\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ExecutorContext } from '@nx/devkit';
2
+ import { ExecutorResult } from '../../executor-result';
3
+ export default function runExecutor(options: Record<string, unknown>, context: ExecutorContext): Promise<ExecutorResult>;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = runExecutor;
4
+ const code_rules_1 = require("@webpieces/code-rules");
5
+ async function runExecutor(
6
+ // webpieces-disable no-any-unknown -- options are passed through to code-rules validators
7
+ options, context) {
8
+ return (0, code_rules_1.validateReturnTypes)(options, context.root);
9
+ }
10
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-return-types/executor.ts"],"names":[],"mappings":";;AAIA,8BAMC;AARD,sDAA4D;AAE7C,KAAK,UAAU,WAAW;AACrC,0FAA0F;AAC1F,OAAgC,EAChC,OAAwB;IAExB,OAAO,IAAA,gCAAmB,EAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { ExecutorResult } from '../../executor-result';\nimport { validateReturnTypes } from '@webpieces/code-rules';\n\nexport default async function runExecutor(\n // webpieces-disable no-any-unknown -- options are passed through to code-rules validators\n options: Record<string, unknown>,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n return validateReturnTypes(options, context.root);\n}\n"]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Validate TypeScript Files in src/ Executor
3
+ *
4
+ * Two-layer rule:
5
+ * Layer 1: every .ts file inside an Nx project must live under src/
6
+ * (jest.config.ts at project root is the only exception)
7
+ * Layer 2: every .ts file anywhere in the workspace must belong to some
8
+ * Nx project. Orphan files (at workspace root or in a non-project
9
+ * directory) fail the rule unless explicitly allowlisted.
10
+ *
11
+ * Configurable via nx.json targetDefaults:
12
+ * "validate-ts-in-src": {
13
+ * "options": {
14
+ * "mode": "ON",
15
+ * "excludePaths": [...],
16
+ * "allowedRootFiles": [...]
17
+ * }
18
+ * }
19
+ *
20
+ * Usage: nx run architecture:validate-ts-in-src
21
+ */
22
+ import type { ExecutorContext } from '@nx/devkit';
23
+ export type ValidateTsInSrcMode = 'ON' | 'OFF';
24
+ export interface ValidateTsInSrcOptions {
25
+ mode?: ValidateTsInSrcMode;
26
+ excludePaths?: string[];
27
+ allowedRootFiles?: string[];
28
+ }
29
+ export interface ExecutorResult {
30
+ success: boolean;
31
+ }
32
+ export default function runExecutor(_nxOptions: ValidateTsInSrcOptions, context: ExecutorContext): Promise<ExecutorResult>;
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Validate TypeScript Files in src/ Executor
3
4
  *
@@ -19,139 +20,117 @@
19
20
  *
20
21
  * Usage: nx run architecture:validate-ts-in-src
21
22
  */
22
-
23
- import type { ExecutorContext } from '@nx/devkit';
24
- import { createProjectGraphAsync, readProjectsConfigurationFromProjectGraph } from '@nx/devkit';
25
- import { loadConfig } from '@webpieces/rules-config';
26
- import * as fs from 'fs';
27
- import * as path from 'path';
28
-
29
- export type ValidateTsInSrcMode = 'ON' | 'OFF';
30
-
31
- export interface ValidateTsInSrcOptions {
32
- mode?: ValidateTsInSrcMode;
33
- excludePaths?: string[];
34
- allowedRootFiles?: string[];
35
- }
36
-
37
- export interface ExecutorResult {
38
- success: boolean;
39
- }
40
-
41
- const DEFAULT_EXCLUDE_PATHS: string[] = [
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.default = runExecutor;
25
+ const tslib_1 = require("tslib");
26
+ const devkit_1 = require("@nx/devkit");
27
+ const rules_config_1 = require("@webpieces/rules-config");
28
+ const fs = tslib_1.__importStar(require("fs"));
29
+ const path = tslib_1.__importStar(require("path"));
30
+ const DEFAULT_EXCLUDE_PATHS = [
42
31
  'node_modules', 'dist', '.nx', '.git',
43
32
  'architecture', 'tmp', 'scripts',
44
33
  ];
45
-
46
- const DEFAULT_ALLOWED_ROOT_FILES: string[] = ['jest.setup.ts'];
47
-
34
+ const DEFAULT_ALLOWED_ROOT_FILES = ['jest.setup.ts'];
48
35
  class LayerOneViolation {
49
- filePath: string;
50
- projectName: string;
51
-
52
- constructor(filePath: string, projectName: string) {
36
+ constructor(filePath, projectName) {
53
37
  this.filePath = filePath;
54
38
  this.projectName = projectName;
55
39
  }
56
40
  }
57
-
58
41
  class LayerTwoViolation {
59
- filePath: string;
60
-
61
- constructor(filePath: string) {
42
+ constructor(filePath) {
62
43
  this.filePath = filePath;
63
44
  }
64
45
  }
65
-
66
- function isNodeModulesDir(name: string): boolean {
46
+ function isNodeModulesDir(name) {
67
47
  return name === 'node_modules' || name.startsWith('node_modules_');
68
48
  }
69
-
70
- function shouldSkipTopLevelDir(name: string, excludePaths: string[]): boolean {
71
- if (isNodeModulesDir(name)) return true;
49
+ function shouldSkipTopLevelDir(name, excludePaths) {
50
+ if (isNodeModulesDir(name))
51
+ return true;
72
52
  return excludePaths.includes(name);
73
53
  }
74
-
75
- async function getProjectRoots(workspaceRoot: string): Promise<string[]> {
76
- const projectGraph = await createProjectGraphAsync();
77
- const projectsConfig = readProjectsConfigurationFromProjectGraph(projectGraph);
78
- const roots: string[] = [];
54
+ async function getProjectRoots(workspaceRoot) {
55
+ const projectGraph = await (0, devkit_1.createProjectGraphAsync)();
56
+ const projectsConfig = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
57
+ const roots = [];
79
58
  for (const cfg of Object.values(projectsConfig.projects)) {
80
- if (cfg.root === '' || cfg.root === '.') continue;
81
- if (cfg.root === 'architecture') continue;
59
+ if (cfg.root === '' || cfg.root === '.')
60
+ continue;
61
+ if (cfg.root === 'architecture')
62
+ continue;
82
63
  roots.push(path.join(workspaceRoot, cfg.root));
83
64
  }
84
65
  return roots;
85
66
  }
86
-
87
- function findTsFilesOutsideSrc(projectDir: string): string[] {
88
- const violations: string[] = [];
89
- if (!fs.existsSync(projectDir)) return violations;
67
+ function findTsFilesOutsideSrc(projectDir) {
68
+ const violations = [];
69
+ if (!fs.existsSync(projectDir))
70
+ return violations;
90
71
  const entries = fs.readdirSync(projectDir, { withFileTypes: true });
91
-
92
72
  for (const entry of entries) {
93
- if (entry.name === 'src') continue;
94
- if (isNodeModulesDir(entry.name)) continue;
95
- if (entry.name === 'dist') continue;
96
-
73
+ if (entry.name === 'src')
74
+ continue;
75
+ if (isNodeModulesDir(entry.name))
76
+ continue;
77
+ if (entry.name === 'dist')
78
+ continue;
97
79
  if (entry.isFile() && entry.name.endsWith('.ts')) {
98
- if (entry.name === 'jest.config.ts') continue;
80
+ if (entry.name === 'jest.config.ts')
81
+ continue;
99
82
  violations.push(path.join(projectDir, entry.name));
100
83
  }
101
-
102
84
  if (entry.isDirectory()) {
103
85
  const tsFiles = findTsFilesRecursively(path.join(projectDir, entry.name));
104
86
  violations.push(...tsFiles);
105
87
  }
106
88
  }
107
-
108
89
  return violations;
109
90
  }
110
-
111
- function findTsFilesRecursively(dir: string): string[] {
112
- const results: string[] = [];
113
- if (!fs.existsSync(dir)) return results;
114
-
91
+ function findTsFilesRecursively(dir) {
92
+ const results = [];
93
+ if (!fs.existsSync(dir))
94
+ return results;
115
95
  const entries = fs.readdirSync(dir, { withFileTypes: true });
116
96
  for (const entry of entries) {
117
- if (isNodeModulesDir(entry.name)) continue;
118
- if (entry.name === 'dist') continue;
97
+ if (isNodeModulesDir(entry.name))
98
+ continue;
99
+ if (entry.name === 'dist')
100
+ continue;
119
101
  const fullPath = path.join(dir, entry.name);
120
102
  if (entry.isFile() && entry.name.endsWith('.ts')) {
121
103
  results.push(fullPath);
122
- } else if (entry.isDirectory()) {
104
+ }
105
+ else if (entry.isDirectory()) {
123
106
  results.push(...findTsFilesRecursively(fullPath));
124
107
  }
125
108
  }
126
109
  return results;
127
110
  }
128
-
129
- function findOrphanTsFiles(
130
- dir: string,
131
- projectRootSet: Set<string>,
132
- workspaceRoot: string,
133
- results: string[],
134
- ): void {
135
- if (!fs.existsSync(dir)) return;
136
-
111
+ function findOrphanTsFiles(dir, projectRootSet, workspaceRoot, results) {
112
+ if (!fs.existsSync(dir))
113
+ return;
137
114
  const relDir = path.relative(workspaceRoot, dir);
138
- if (projectRootSet.has(relDir)) return;
139
-
115
+ if (projectRootSet.has(relDir))
116
+ return;
140
117
  const entries = fs.readdirSync(dir, { withFileTypes: true });
141
118
  for (const entry of entries) {
142
- if (isNodeModulesDir(entry.name)) continue;
143
- if (entry.name === 'dist') continue;
119
+ if (isNodeModulesDir(entry.name))
120
+ continue;
121
+ if (entry.name === 'dist')
122
+ continue;
144
123
  const fullPath = path.join(dir, entry.name);
145
124
  if (entry.isFile() && entry.name.endsWith('.ts')) {
146
125
  results.push(fullPath);
147
- } else if (entry.isDirectory()) {
126
+ }
127
+ else if (entry.isDirectory()) {
148
128
  findOrphanTsFiles(fullPath, projectRootSet, workspaceRoot, results);
149
129
  }
150
130
  }
151
131
  }
152
-
153
- function checkLayerOne(projectRoots: string[], workspaceRoot: string): LayerOneViolation[] {
154
- const violations: LayerOneViolation[] = [];
132
+ function checkLayerOne(projectRoots, workspaceRoot) {
133
+ const violations = [];
155
134
  for (const projectDir of projectRoots) {
156
135
  const projectName = path.relative(workspaceRoot, projectDir);
157
136
  const tsFiles = findTsFilesOutsideSrc(projectDir);
@@ -162,46 +141,32 @@ function checkLayerOne(projectRoots: string[], workspaceRoot: string): LayerOneV
162
141
  }
163
142
  return violations;
164
143
  }
165
-
166
- function checkLayerTwo(
167
- workspaceRoot: string,
168
- projectRoots: string[],
169
- excludePaths: string[],
170
- allowedRootFiles: string[],
171
- ): LayerTwoViolation[] {
172
- const violations: LayerTwoViolation[] = [];
173
- const projectRootSet = new Set(
174
- projectRoots.map((p) => path.relative(workspaceRoot, p)),
175
- );
176
-
144
+ function checkLayerTwo(workspaceRoot, projectRoots, excludePaths, allowedRootFiles) {
145
+ const violations = [];
146
+ const projectRootSet = new Set(projectRoots.map((p) => path.relative(workspaceRoot, p)));
177
147
  const entries = fs.readdirSync(workspaceRoot, { withFileTypes: true });
178
-
179
148
  for (const entry of entries) {
180
149
  if (entry.isFile()) {
181
- if (!entry.name.endsWith('.ts')) continue;
182
- if (allowedRootFiles.includes(entry.name)) continue;
150
+ if (!entry.name.endsWith('.ts'))
151
+ continue;
152
+ if (allowedRootFiles.includes(entry.name))
153
+ continue;
183
154
  violations.push(new LayerTwoViolation(entry.name));
184
155
  continue;
185
156
  }
186
- if (!entry.isDirectory()) continue;
187
- if (shouldSkipTopLevelDir(entry.name, excludePaths)) continue;
188
-
189
- const orphans: string[] = [];
190
- findOrphanTsFiles(
191
- path.join(workspaceRoot, entry.name),
192
- projectRootSet,
193
- workspaceRoot,
194
- orphans,
195
- );
157
+ if (!entry.isDirectory())
158
+ continue;
159
+ if (shouldSkipTopLevelDir(entry.name, excludePaths))
160
+ continue;
161
+ const orphans = [];
162
+ findOrphanTsFiles(path.join(workspaceRoot, entry.name), projectRootSet, workspaceRoot, orphans);
196
163
  for (const orphan of orphans) {
197
164
  violations.push(new LayerTwoViolation(path.relative(workspaceRoot, orphan)));
198
165
  }
199
166
  }
200
-
201
167
  return violations;
202
168
  }
203
-
204
- function reportLayerOneFailure(violations: LayerOneViolation[]): void {
169
+ function reportLayerOneFailure(violations) {
205
170
  console.error('❌ TypeScript files found outside src/ directory!\n');
206
171
  console.error('All .ts source files must be inside the project\'s src/ directory.');
207
172
  console.error('This enforces the standard project structure:\n');
@@ -210,25 +175,20 @@ function reportLayerOneFailure(violations: LayerOneViolation[]): void {
210
175
  console.error(' ├── package.json');
211
176
  console.error(' ├── project.json');
212
177
  console.error(' └── tsconfig.json\n');
213
-
214
178
  for (const v of violations) {
215
179
  console.error(` ❌ ${v.filePath}`);
216
180
  }
217
-
218
181
  console.error('\nTo fix: Move the .ts file(s) into the src/ directory');
219
182
  console.error('Only exception: jest.config.ts at project root\n');
220
183
  }
221
-
222
- function reportLayerTwoFailure(violations: LayerTwoViolation[]): void {
184
+ function reportLayerTwoFailure(violations) {
223
185
  console.error('❌ TypeScript files found outside any Nx project!\n');
224
186
  console.error('Every .ts file must belong to an Nx project so it is compiled,');
225
187
  console.error('linted, and tested under a known project config. Orphan files are');
226
188
  console.error('invisible to the build graph and will rot.\n');
227
-
228
189
  for (const v of violations) {
229
190
  console.error(` ❌ ${v.filePath}`);
230
191
  }
231
-
232
192
  console.error('\nTo fix, pick one:');
233
193
  console.error(' (a) Move the file into an existing project\'s src/ directory');
234
194
  console.error(' (b) Create a new project (add project.json) that owns the directory');
@@ -236,48 +196,33 @@ function reportLayerTwoFailure(violations: LayerTwoViolation[]): void {
236
196
  console.error(' in nx.json targetDefaults, or add the filename to allowedRootFiles');
237
197
  console.error(' if it is a legitimate workspace-root file (e.g., jest.setup.ts)\n');
238
198
  }
239
-
240
- export default async function runExecutor(
241
- _nxOptions: ValidateTsInSrcOptions,
242
- context: ExecutorContext,
243
- ): Promise<ExecutorResult> {
199
+ async function runExecutor(_nxOptions, context) {
244
200
  // Config comes from webpieces.config.json — same source as ai-hooks
245
201
  // and validate-code — via @webpieces/rules-config.
246
- const shared = loadConfig(context.root);
202
+ const shared = (0, rules_config_1.loadConfig)(context.root);
247
203
  const rule = shared.rules.get('validate-ts-in-src');
248
-
249
204
  if (rule && rule.enabled === false) {
250
205
  console.log('\n⏭️ Skipping validate-ts-in-src (enabled: false)\n');
251
206
  return { success: true };
252
207
  }
253
-
254
208
  const workspaceRoot = context.root;
255
- const excludePaths =
256
- (rule?.options['excludePaths'] as string[] | undefined) ?? DEFAULT_EXCLUDE_PATHS;
257
- const allowedRootFiles =
258
- (rule?.options['allowedRootFiles'] as string[] | undefined) ?? DEFAULT_ALLOWED_ROOT_FILES;
259
-
209
+ const excludePaths = rule?.options['excludePaths'] ?? DEFAULT_EXCLUDE_PATHS;
210
+ const allowedRootFiles = rule?.options['allowedRootFiles'] ?? DEFAULT_ALLOWED_ROOT_FILES;
260
211
  console.log('\n📁 Validating TypeScript files are in src/ and owned by a project\n');
261
-
262
212
  const projectRoots = await getProjectRoots(workspaceRoot);
263
-
264
213
  const layerOneViolations = checkLayerOne(projectRoots, workspaceRoot);
265
- const layerTwoViolations = checkLayerTwo(
266
- workspaceRoot, projectRoots, excludePaths, allowedRootFiles,
267
- );
268
-
214
+ const layerTwoViolations = checkLayerTwo(workspaceRoot, projectRoots, excludePaths, allowedRootFiles);
269
215
  if (layerOneViolations.length === 0 && layerTwoViolations.length === 0) {
270
216
  console.log('✅ All .ts files are inside a project\'s src/ directory\n');
271
217
  return { success: true };
272
218
  }
273
-
274
219
  if (layerOneViolations.length > 0) {
275
220
  reportLayerOneFailure(layerOneViolations);
276
221
  }
277
222
  if (layerTwoViolations.length > 0) {
278
223
  reportLayerTwoFailure(layerTwoViolations);
279
224
  }
280
-
281
225
  console.error('To disable: set rules["validate-ts-in-src"].enabled to false in webpieces.config.json\n');
282
226
  return { success: false };
283
227
  }
228
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/validate-ts-in-src/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate TypeScript Files in src/ Executor\n *\n * Two-layer rule:\n * Layer 1: every .ts file inside an Nx project must live under src/\n * (jest.config.ts at project root is the only exception)\n * Layer 2: every .ts file anywhere in the workspace must belong to some\n * Nx project. Orphan files (at workspace root or in a non-project\n * directory) fail the rule unless explicitly allowlisted.\n *\n * Configurable via nx.json targetDefaults:\n * \"validate-ts-in-src\": {\n * \"options\": {\n * \"mode\": \"ON\",\n * \"excludePaths\": [...],\n * \"allowedRootFiles\": [...]\n * }\n * }\n *\n * Usage: nx run architecture:validate-ts-in-src\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { createProjectGraphAsync, readProjectsConfigurationFromProjectGraph } from '@nx/devkit';\nimport { loadConfig } from '@webpieces/rules-config';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nexport type ValidateTsInSrcMode = 'ON' | 'OFF';\n\nexport interface ValidateTsInSrcOptions {\n mode?: ValidateTsInSrcMode;\n excludePaths?: string[];\n allowedRootFiles?: string[];\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nconst DEFAULT_EXCLUDE_PATHS: string[] = [\n 'node_modules', 'dist', '.nx', '.git',\n 'architecture', 'tmp', 'scripts',\n];\n\nconst DEFAULT_ALLOWED_ROOT_FILES: string[] = ['jest.setup.ts'];\n\nclass LayerOneViolation {\n filePath: string;\n projectName: string;\n\n constructor(filePath: string, projectName: string) {\n this.filePath = filePath;\n this.projectName = projectName;\n }\n}\n\nclass LayerTwoViolation {\n filePath: string;\n\n constructor(filePath: string) {\n this.filePath = filePath;\n }\n}\n\nfunction isNodeModulesDir(name: string): boolean {\n return name === 'node_modules' || name.startsWith('node_modules_');\n}\n\nfunction shouldSkipTopLevelDir(name: string, excludePaths: string[]): boolean {\n if (isNodeModulesDir(name)) return true;\n return excludePaths.includes(name);\n}\n\nasync function getProjectRoots(workspaceRoot: string): Promise<string[]> {\n const projectGraph = await createProjectGraphAsync();\n const projectsConfig = readProjectsConfigurationFromProjectGraph(projectGraph);\n const roots: string[] = [];\n for (const cfg of Object.values(projectsConfig.projects)) {\n if (cfg.root === '' || cfg.root === '.') continue;\n if (cfg.root === 'architecture') continue;\n roots.push(path.join(workspaceRoot, cfg.root));\n }\n return roots;\n}\n\nfunction findTsFilesOutsideSrc(projectDir: string): string[] {\n const violations: string[] = [];\n if (!fs.existsSync(projectDir)) return violations;\n const entries = fs.readdirSync(projectDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.name === 'src') continue;\n if (isNodeModulesDir(entry.name)) continue;\n if (entry.name === 'dist') continue;\n\n if (entry.isFile() && entry.name.endsWith('.ts')) {\n if (entry.name === 'jest.config.ts') continue;\n violations.push(path.join(projectDir, entry.name));\n }\n\n if (entry.isDirectory()) {\n const tsFiles = findTsFilesRecursively(path.join(projectDir, entry.name));\n violations.push(...tsFiles);\n }\n }\n\n return violations;\n}\n\nfunction findTsFilesRecursively(dir: string): string[] {\n const results: string[] = [];\n if (!fs.existsSync(dir)) return results;\n\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (isNodeModulesDir(entry.name)) continue;\n if (entry.name === 'dist') continue;\n const fullPath = path.join(dir, entry.name);\n if (entry.isFile() && entry.name.endsWith('.ts')) {\n results.push(fullPath);\n } else if (entry.isDirectory()) {\n results.push(...findTsFilesRecursively(fullPath));\n }\n }\n return results;\n}\n\nfunction findOrphanTsFiles(\n dir: string,\n projectRootSet: Set<string>,\n workspaceRoot: string,\n results: string[],\n): void {\n if (!fs.existsSync(dir)) return;\n\n const relDir = path.relative(workspaceRoot, dir);\n if (projectRootSet.has(relDir)) return;\n\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (isNodeModulesDir(entry.name)) continue;\n if (entry.name === 'dist') continue;\n const fullPath = path.join(dir, entry.name);\n if (entry.isFile() && entry.name.endsWith('.ts')) {\n results.push(fullPath);\n } else if (entry.isDirectory()) {\n findOrphanTsFiles(fullPath, projectRootSet, workspaceRoot, results);\n }\n }\n}\n\nfunction checkLayerOne(projectRoots: string[], workspaceRoot: string): LayerOneViolation[] {\n const violations: LayerOneViolation[] = [];\n for (const projectDir of projectRoots) {\n const projectName = path.relative(workspaceRoot, projectDir);\n const tsFiles = findTsFilesOutsideSrc(projectDir);\n for (const tsFile of tsFiles) {\n const relativePath = path.relative(workspaceRoot, tsFile);\n violations.push(new LayerOneViolation(relativePath, projectName));\n }\n }\n return violations;\n}\n\nfunction checkLayerTwo(\n workspaceRoot: string,\n projectRoots: string[],\n excludePaths: string[],\n allowedRootFiles: string[],\n): LayerTwoViolation[] {\n const violations: LayerTwoViolation[] = [];\n const projectRootSet = new Set(\n projectRoots.map((p) => path.relative(workspaceRoot, p)),\n );\n\n const entries = fs.readdirSync(workspaceRoot, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isFile()) {\n if (!entry.name.endsWith('.ts')) continue;\n if (allowedRootFiles.includes(entry.name)) continue;\n violations.push(new LayerTwoViolation(entry.name));\n continue;\n }\n if (!entry.isDirectory()) continue;\n if (shouldSkipTopLevelDir(entry.name, excludePaths)) continue;\n\n const orphans: string[] = [];\n findOrphanTsFiles(\n path.join(workspaceRoot, entry.name),\n projectRootSet,\n workspaceRoot,\n orphans,\n );\n for (const orphan of orphans) {\n violations.push(new LayerTwoViolation(path.relative(workspaceRoot, orphan)));\n }\n }\n\n return violations;\n}\n\nfunction reportLayerOneFailure(violations: LayerOneViolation[]): void {\n console.error('❌ TypeScript files found outside src/ directory!\\n');\n console.error('All .ts source files must be inside the project\\'s src/ directory.');\n console.error('This enforces the standard project structure:\\n');\n console.error(' packages/{category}/{name}/');\n console.error(' ├── src/ ← ALL .ts files here');\n console.error(' ├── package.json');\n console.error(' ├── project.json');\n console.error(' └── tsconfig.json\\n');\n\n for (const v of violations) {\n console.error(` ❌ ${v.filePath}`);\n }\n\n console.error('\\nTo fix: Move the .ts file(s) into the src/ directory');\n console.error('Only exception: jest.config.ts at project root\\n');\n}\n\nfunction reportLayerTwoFailure(violations: LayerTwoViolation[]): void {\n console.error('❌ TypeScript files found outside any Nx project!\\n');\n console.error('Every .ts file must belong to an Nx project so it is compiled,');\n console.error('linted, and tested under a known project config. Orphan files are');\n console.error('invisible to the build graph and will rot.\\n');\n\n for (const v of violations) {\n console.error(` ❌ ${v.filePath}`);\n }\n\n console.error('\\nTo fix, pick one:');\n console.error(' (a) Move the file into an existing project\\'s src/ directory');\n console.error(' (b) Create a new project (add project.json) that owns the directory');\n console.error(' (c) Add the containing top-level directory to validate-ts-in-src.excludePaths');\n console.error(' in nx.json targetDefaults, or add the filename to allowedRootFiles');\n console.error(' if it is a legitimate workspace-root file (e.g., jest.setup.ts)\\n');\n}\n\nexport default async function runExecutor(\n _nxOptions: ValidateTsInSrcOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n // Config comes from webpieces.config.json — same source as ai-hooks\n // and validate-code — via @webpieces/rules-config.\n const shared = loadConfig(context.root);\n const rule = shared.rules.get('validate-ts-in-src');\n\n if (rule && rule.enabled === false) {\n console.log('\\n⏭️ Skipping validate-ts-in-src (enabled: false)\\n');\n return { success: true };\n }\n\n const workspaceRoot = context.root;\n const excludePaths =\n (rule?.options['excludePaths'] as string[] | undefined) ?? DEFAULT_EXCLUDE_PATHS;\n const allowedRootFiles =\n (rule?.options['allowedRootFiles'] as string[] | undefined) ?? DEFAULT_ALLOWED_ROOT_FILES;\n\n console.log('\\n📁 Validating TypeScript files are in src/ and owned by a project\\n');\n\n const projectRoots = await getProjectRoots(workspaceRoot);\n\n const layerOneViolations = checkLayerOne(projectRoots, workspaceRoot);\n const layerTwoViolations = checkLayerTwo(\n workspaceRoot, projectRoots, excludePaths, allowedRootFiles,\n );\n\n if (layerOneViolations.length === 0 && layerTwoViolations.length === 0) {\n console.log('✅ All .ts files are inside a project\\'s src/ directory\\n');\n return { success: true };\n }\n\n if (layerOneViolations.length > 0) {\n reportLayerOneFailure(layerOneViolations);\n }\n if (layerTwoViolations.length > 0) {\n reportLayerTwoFailure(layerTwoViolations);\n }\n\n console.error('To disable: set rules[\"validate-ts-in-src\"].enabled to false in webpieces.config.json\\n');\n return { success: false };\n}\n"]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Validate Versions Locked Executor
3
+ *
4
+ * Validates that package.json versions are:
5
+ * 1. LOCKED (exact versions, no semver ranges like ^, ~, *)
6
+ * 2. CONSISTENT across all package.json files (no version conflicts)
7
+ *
8
+ * Why locked versions matter:
9
+ * - Micro bugs ARE introduced via patch versions (1.4.5 → 1.4.6)
10
+ * - git bisect fails when software changes OUTSIDE of git
11
+ * - Library upgrades must be explicit via PR/commit, not implicit drift
12
+ *
13
+ * Usage:
14
+ * nx run architecture:validate-versions-locked
15
+ */
16
+ import type { ExecutorContext } from '@nx/devkit';
17
+ export interface ValidateVersionsLockedOptions {
18
+ }
19
+ export interface ExecutorResult {
20
+ success: boolean;
21
+ }
22
+ export default function runExecutor(_options: ValidateVersionsLockedOptions, context: ExecutorContext): Promise<ExecutorResult>;