@webpieces/nx-webpieces-rules 0.0.1

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 (61) hide show
  1. package/LICENSE +373 -0
  2. package/executors.json +124 -0
  3. package/package.json +36 -0
  4. package/src/executor-result.ts +7 -0
  5. package/src/executors/generate/executor.ts +61 -0
  6. package/src/executors/generate/schema.json +14 -0
  7. package/src/executors/help/executor.ts +63 -0
  8. package/src/executors/help/schema.json +7 -0
  9. package/src/executors/validate-architecture-unchanged/executor.ts +253 -0
  10. package/src/executors/validate-architecture-unchanged/schema.json +14 -0
  11. package/src/executors/validate-catch-error-pattern/executor.ts +11 -0
  12. package/src/executors/validate-catch-error-pattern/schema.json +24 -0
  13. package/src/executors/validate-code/executor.ts +11 -0
  14. package/src/executors/validate-code/schema.json +287 -0
  15. package/src/executors/validate-dtos/executor.ts +11 -0
  16. package/src/executors/validate-dtos/schema.json +33 -0
  17. package/src/executors/validate-eslint-sync/executor.ts +87 -0
  18. package/src/executors/validate-eslint-sync/schema.json +7 -0
  19. package/src/executors/validate-modified-files/executor.ts +11 -0
  20. package/src/executors/validate-modified-files/schema.json +25 -0
  21. package/src/executors/validate-modified-methods/executor.ts +11 -0
  22. package/src/executors/validate-modified-methods/schema.json +25 -0
  23. package/src/executors/validate-new-methods/executor.ts +11 -0
  24. package/src/executors/validate-new-methods/schema.json +25 -0
  25. package/src/executors/validate-no-any-unknown/executor.ts +11 -0
  26. package/src/executors/validate-no-any-unknown/schema.json +24 -0
  27. package/src/executors/validate-no-architecture-cycles/executor.ts +63 -0
  28. package/src/executors/validate-no-architecture-cycles/schema.json +8 -0
  29. package/src/executors/validate-no-destructure/executor.ts +11 -0
  30. package/src/executors/validate-no-destructure/schema.json +24 -0
  31. package/src/executors/validate-no-direct-api-resolver/executor.ts +11 -0
  32. package/src/executors/validate-no-direct-api-resolver/schema.json +29 -0
  33. package/src/executors/validate-no-implicit-any/executor.ts +11 -0
  34. package/src/executors/validate-no-implicit-any/schema.json +24 -0
  35. package/src/executors/validate-no-inline-types/executor.ts +11 -0
  36. package/src/executors/validate-no-inline-types/schema.json +24 -0
  37. package/src/executors/validate-no-skiplevel-deps/executor.ts +274 -0
  38. package/src/executors/validate-no-skiplevel-deps/schema.json +8 -0
  39. package/src/executors/validate-no-unmanaged-exceptions/executor.ts +11 -0
  40. package/src/executors/validate-no-unmanaged-exceptions/schema.json +24 -0
  41. package/src/executors/validate-packagejson/executor.ts +76 -0
  42. package/src/executors/validate-packagejson/schema.json +8 -0
  43. package/src/executors/validate-prisma-converters/executor.ts +11 -0
  44. package/src/executors/validate-prisma-converters/schema.json +38 -0
  45. package/src/executors/validate-return-types/executor.ts +11 -0
  46. package/src/executors/validate-return-types/schema.json +24 -0
  47. package/src/executors/validate-ts-in-src/executor.ts +283 -0
  48. package/src/executors/validate-ts-in-src/schema.json +25 -0
  49. package/src/executors/validate-versions-locked/executor.ts +376 -0
  50. package/src/executors/validate-versions-locked/schema.json +8 -0
  51. package/src/executors/visualize/executor.ts +65 -0
  52. package/src/executors/visualize/schema.json +14 -0
  53. package/src/index.ts +9 -0
  54. package/src/lib/graph-comparator.ts +154 -0
  55. package/src/lib/graph-generator.ts +97 -0
  56. package/src/lib/graph-loader.ts +119 -0
  57. package/src/lib/graph-sorter.ts +137 -0
  58. package/src/lib/graph-visualizer.ts +253 -0
  59. package/src/lib/package-validator.ts +184 -0
  60. package/src/plugin.ts +666 -0
  61. package/src/toError.ts +36 -0
@@ -0,0 +1,287 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "title": "Validate Code Executor",
4
+ "description": "Combined validation for new methods, modified methods, and file sizes. Configure via targetDefaults in nx.json for runtime options (no cache issues).",
5
+ "type": "object",
6
+ "properties": {
7
+ "methodMaxLimit": {
8
+ "type": "object",
9
+ "description": "Configuration for method line limit validation",
10
+ "properties": {
11
+ "limit": {
12
+ "type": "number",
13
+ "description": "Maximum lines allowed for methods",
14
+ "default": 80
15
+ },
16
+ "mode": {
17
+ "type": "string",
18
+ "description": "OFF: skip validation. NEW_METHODS: only new methods in diff. NEW_AND_MODIFIED_METHODS: new methods + methods with changes. MODIFIED_FILES: all methods in modified files.",
19
+ "default": "NEW_AND_MODIFIED_METHODS"
20
+ },
21
+ "disableAllowed": {
22
+ "type": "boolean",
23
+ "description": "Whether disable comments work. When false, no escape hatch (like old STRICT mode).",
24
+ "default": true
25
+ },
26
+ "ignoreModifiedUntilEpoch": {
27
+ "type": "number",
28
+ "description": "Epoch seconds. Until this time, skip modified-method validation (new methods still enforced). When expired, normal mode resumes. Omit when not needed."
29
+ }
30
+ }
31
+ },
32
+ "fileMaxLimit": {
33
+ "type": "object",
34
+ "description": "Configuration for file line limit validation",
35
+ "properties": {
36
+ "limit": {
37
+ "type": "number",
38
+ "description": "Maximum lines for modified files",
39
+ "default": 900
40
+ },
41
+ "mode": {
42
+ "type": "string",
43
+ "description": "OFF: skip validation. MODIFIED_FILES: all code in modified files.",
44
+ "default": "MODIFIED_FILES"
45
+ },
46
+ "disableAllowed": {
47
+ "type": "boolean",
48
+ "description": "Whether disable comments work. When false, no escape hatch (like old STRICT mode).",
49
+ "default": true
50
+ },
51
+ "ignoreModifiedUntilEpoch": {
52
+ "type": "number",
53
+ "description": "Epoch seconds. Until this time, skip modified-file validation. When expired, normal mode resumes. Omit when not needed."
54
+ }
55
+ }
56
+ },
57
+ "requireReturnType": {
58
+ "type": "object",
59
+ "description": "Configuration for return type validation",
60
+ "properties": {
61
+ "mode": {
62
+ "type": "string",
63
+ "description": "OFF: skip return type validation. NEW_METHODS: only new methods in diff. NEW_AND_MODIFIED_METHODS: new methods + methods with changes. MODIFIED_FILES: all methods in modified files.",
64
+ "default": "OFF"
65
+ },
66
+ "disableAllowed": {
67
+ "type": "boolean",
68
+ "description": "Whether disable comments work. When false, no escape hatch.",
69
+ "default": true
70
+ },
71
+ "ignoreModifiedUntilEpoch": {
72
+ "type": "number",
73
+ "description": "Epoch seconds. Until this time, skip validation entirely. When expired, normal mode resumes. Omit when not needed."
74
+ }
75
+ }
76
+ },
77
+ "noInlineTypeLiterals": {
78
+ "type": "object",
79
+ "description": "Configuration for no-inline-types validation",
80
+ "properties": {
81
+ "mode": {
82
+ "type": "string",
83
+ "description": "OFF: skip validation. NEW_METHODS: only new methods. NEW_AND_MODIFIED_METHODS: new + modified methods. MODIFIED_FILES: all in modified files. Disallows inline type literals like { x: number } - use named types instead.",
84
+ "default": "OFF"
85
+ },
86
+ "disableAllowed": {
87
+ "type": "boolean",
88
+ "description": "Whether disable comments work. When false, no escape hatch.",
89
+ "default": true
90
+ },
91
+ "ignoreModifiedUntilEpoch": {
92
+ "type": "number",
93
+ "description": "Epoch seconds. Until this time, skip validation entirely. When expired, normal mode resumes. Omit when not needed."
94
+ }
95
+ }
96
+ },
97
+ "noAnyUnknown": {
98
+ "type": "object",
99
+ "description": "Configuration for no-any-unknown validation",
100
+ "properties": {
101
+ "mode": {
102
+ "type": "string",
103
+ "description": "OFF: skip validation. MODIFIED_CODE: only changed lines in diff. MODIFIED_FILES: all in modified files. Disallows `any` and `unknown` TypeScript keywords.",
104
+ "default": "OFF"
105
+ },
106
+ "disableAllowed": {
107
+ "type": "boolean",
108
+ "description": "Whether disable comments work. When false, no escape hatch.",
109
+ "default": true
110
+ },
111
+ "ignoreModifiedUntilEpoch": {
112
+ "type": "number",
113
+ "description": "Epoch seconds. Until this time, skip validation entirely. When expired, normal mode resumes. Omit when not needed."
114
+ }
115
+ }
116
+ },
117
+ "noImplicitAny": {
118
+ "type": "object",
119
+ "description": "Configuration for no-implicit-any validation (TS7006/7005/7018/etc via the TypeScript compiler).",
120
+ "properties": {
121
+ "mode": {
122
+ "type": "string",
123
+ "description": "OFF: skip validation. MODIFIED_CODE: only implicit-any on changed lines. MODIFIED_FILES: all implicit-any in modified files.",
124
+ "default": "OFF"
125
+ },
126
+ "disableAllowed": {
127
+ "type": "boolean",
128
+ "description": "Whether // webpieces-disable no-implicit-any comments work. When false, no escape hatch.",
129
+ "default": true
130
+ },
131
+ "ignoreModifiedUntilEpoch": {
132
+ "type": "number",
133
+ "description": "Epoch seconds. Until this time, skip validation entirely. When expired, normal mode resumes. Omit when not needed."
134
+ }
135
+ }
136
+ },
137
+ "validateDtos": {
138
+ "type": "object",
139
+ "description": "Validate DTO fields match Prisma Dbo model fields. Prevents AI from inventing field names.",
140
+ "properties": {
141
+ "mode": {
142
+ "type": "string",
143
+ "description": "OFF: skip validation. MODIFIED_CLASS: only validate Dto classes with changed lines. MODIFIED_FILES: validate all Dtos in modified files.",
144
+ "default": "OFF"
145
+ },
146
+ "disableAllowed": {
147
+ "type": "boolean",
148
+ "description": "Whether @deprecated field exemption works. When false, all fields must match.",
149
+ "default": true
150
+ },
151
+ "prismaSchemaPath": {
152
+ "type": "string",
153
+ "description": "Relative path from workspace root to schema.prisma"
154
+ },
155
+ "dtoSourcePaths": {
156
+ "type": "array",
157
+ "items": { "type": "string" },
158
+ "description": "Array of directories (relative to workspace root) containing Dto files"
159
+ },
160
+ "ignoreModifiedUntilEpoch": {
161
+ "type": "number",
162
+ "description": "Epoch seconds. Until this time, skip DTO validation entirely. When expired, normal mode resumes. Omit when not needed."
163
+ }
164
+ }
165
+ },
166
+ "prismaConverter": {
167
+ "type": "object",
168
+ "description": "Validate Prisma converter methods follow scalable patterns: correct Dbo parameter, no async, no standalone functions, Dto creation only in converter directories.",
169
+ "properties": {
170
+ "mode": {
171
+ "type": "string",
172
+ "description": "OFF: skip validation. NEW_AND_MODIFIED_METHODS: validate new/modified methods in converters + changed lines in non-converters. MODIFIED_FILES: validate all methods in modified files.",
173
+ "default": "OFF"
174
+ },
175
+ "disableAllowed": {
176
+ "type": "boolean",
177
+ "description": "Whether disable comments work. When false, no escape hatch.",
178
+ "default": true
179
+ },
180
+ "schemaPath": {
181
+ "type": "string",
182
+ "description": "Relative path from workspace root to schema.prisma"
183
+ },
184
+ "convertersPaths": {
185
+ "type": "array",
186
+ "items": { "type": "string" },
187
+ "description": "Array of directories (relative to workspace root) containing converter files"
188
+ },
189
+ "enforcePaths": {
190
+ "type": "array",
191
+ "items": { "type": "string" },
192
+ "description": "Array of directory prefixes (relative to workspace root) to scope validation to. When set, only files under these paths are checked. When empty/omitted, all changed files are checked."
193
+ },
194
+ "ignoreModifiedUntilEpoch": {
195
+ "type": "number",
196
+ "description": "Epoch seconds. Until this time, skip prisma-converter validation entirely. When expired, normal mode resumes. Omit when not needed."
197
+ }
198
+ }
199
+ },
200
+ "noDestructure": {
201
+ "type": "object",
202
+ "description": "Validate no destructuring patterns are used. Destructuring hurts code traceability.",
203
+ "properties": {
204
+ "mode": {
205
+ "type": "string",
206
+ "description": "OFF: skip validation. MODIFIED_CODE: only changed lines in diff. MODIFIED_FILES: all in modified files. Disallows destructuring patterns.",
207
+ "default": "OFF"
208
+ },
209
+ "disableAllowed": {
210
+ "type": "boolean",
211
+ "description": "Whether disable comments work. When false, no escape hatch.",
212
+ "default": true
213
+ },
214
+ "ignoreModifiedUntilEpoch": {
215
+ "type": "number",
216
+ "description": "Epoch seconds. Until this time, skip validation entirely. When expired, normal mode resumes. Omit when not needed."
217
+ }
218
+ }
219
+ },
220
+ "catchErrorPattern": {
221
+ "type": "object",
222
+ "description": "Validate catch blocks follow standardized pattern: catch (err: unknown) { const error = toError(err); }",
223
+ "properties": {
224
+ "mode": {
225
+ "type": "string",
226
+ "description": "OFF: skip validation. MODIFIED_CODE: only catch blocks on changed lines. MODIFIED_FILES: all catch blocks in modified files.",
227
+ "default": "OFF"
228
+ },
229
+ "disableAllowed": {
230
+ "type": "boolean",
231
+ "description": "Whether disable comments work. When false, no escape hatch.",
232
+ "default": true
233
+ },
234
+ "ignoreModifiedUntilEpoch": {
235
+ "type": "number",
236
+ "description": "Epoch seconds. Until this time, skip validation entirely. When expired, normal mode resumes. Omit when not needed."
237
+ }
238
+ }
239
+ },
240
+ "noUnmanagedExceptions": {
241
+ "type": "object",
242
+ "description": "Validate try/catch blocks are not used outside chokepoints. Exceptions should bubble to filters/globalErrorHandlers.",
243
+ "properties": {
244
+ "mode": {
245
+ "type": "string",
246
+ "description": "OFF: skip validation. MODIFIED_CODE: only changed lines in diff. MODIFIED_FILES: all in modified files. Disallows try/catch blocks.",
247
+ "default": "OFF"
248
+ },
249
+ "disableAllowed": {
250
+ "type": "boolean",
251
+ "description": "Whether disable comments work. When false, no escape hatch.",
252
+ "default": true
253
+ },
254
+ "ignoreModifiedUntilEpoch": {
255
+ "type": "number",
256
+ "description": "Epoch seconds. Until this time, skip validation entirely. When expired, normal mode resumes. Omit when not needed."
257
+ }
258
+ }
259
+ },
260
+ "noDirectApiInResolver": {
261
+ "type": "object",
262
+ "description": "Validate resolvers use services (not APIs) and components subscribe to service observables (not route.snapshot.data).",
263
+ "properties": {
264
+ "mode": {
265
+ "type": "string",
266
+ "description": "OFF: skip validation. MODIFIED_CODE: only changed lines in diff. NEW_AND_MODIFIED_METHODS: violations in new/modified method/route scopes. MODIFIED_FILES: all in modified files.",
267
+ "default": "OFF"
268
+ },
269
+ "disableAllowed": {
270
+ "type": "boolean",
271
+ "description": "Whether disable comments work. When false, no escape hatch.",
272
+ "default": true
273
+ },
274
+ "ignoreModifiedUntilEpoch": {
275
+ "type": "number",
276
+ "description": "Epoch seconds. Until this time, skip validation entirely. When expired, normal mode resumes. Omit when not needed."
277
+ },
278
+ "enforcePaths": {
279
+ "type": "array",
280
+ "items": { "type": "string" },
281
+ "description": "Array of directory prefixes (relative to workspace root) to scope validation to. When set, only files under these paths are checked. When empty/omitted, all changed files are checked."
282
+ }
283
+ }
284
+ }
285
+ },
286
+ "required": []
287
+ }
@@ -0,0 +1,11 @@
1
+ import type { ExecutorContext } from '@nx/devkit';
2
+ import { ExecutorResult } from '../../executor-result';
3
+ import { validateDtos } from '@webpieces/code-rules';
4
+
5
+ export default async function runExecutor(
6
+ // webpieces-disable no-any-unknown -- options are passed through to code-rules validators
7
+ options: Record<string, unknown>,
8
+ context: ExecutorContext,
9
+ ): Promise<ExecutorResult> {
10
+ return validateDtos(options, context.root);
11
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "title": "Validate DTOs Executor",
4
+ "description": "Validate DTO fields match Prisma Dbo model fields. Ensures AI agents don't invent field names.",
5
+ "type": "object",
6
+ "properties": {
7
+ "mode": {
8
+ "type": "string",
9
+ "enum": ["OFF", "MODIFIED_CLASS", "MODIFIED_FILES"],
10
+ "description": "OFF: skip validation. MODIFIED_CLASS: only validate Dto classes with changed lines. MODIFIED_FILES: validate all Dtos in modified files.",
11
+ "default": "OFF"
12
+ },
13
+ "prismaSchemaPath": {
14
+ "type": "string",
15
+ "description": "Relative path from workspace root to schema.prisma"
16
+ },
17
+ "dtoSourcePaths": {
18
+ "type": "array",
19
+ "items": { "type": "string" },
20
+ "description": "Array of directories (relative to workspace root) containing Dto files"
21
+ },
22
+ "disableAllowed": {
23
+ "type": "boolean",
24
+ "description": "Whether @deprecated field exemption works. When false, all fields must match.",
25
+ "default": true
26
+ },
27
+ "ignoreModifiedUntilEpoch": {
28
+ "type": "number",
29
+ "description": "Epoch seconds. Until this time, skip DTO validation entirely. When expired, normal mode resumes. Omit when not needed."
30
+ }
31
+ },
32
+ "required": []
33
+ }
@@ -0,0 +1,87 @@
1
+ import type { ExecutorContext } from '@nx/devkit';
2
+ import { readFileSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { createHash } from 'crypto';
5
+
6
+ export interface ValidateEslintSyncOptions {}
7
+
8
+ export interface ExecutorResult {
9
+ success: boolean;
10
+ }
11
+
12
+ function calculateHash(content: string): string {
13
+ return createHash('sha256').update(content).digest('hex');
14
+ }
15
+
16
+ function normalizeContent(content: string): string {
17
+ // Normalize line endings and trim whitespace
18
+ return content.replace(/\r\n/g, '\n').trim();
19
+ }
20
+
21
+ export default async function validateEslintSyncExecutor(
22
+ options: ValidateEslintSyncOptions,
23
+ context: ExecutorContext
24
+ ): Promise<ExecutorResult> {
25
+ const workspaceRoot = context.root;
26
+
27
+ const templatePath = join(workspaceRoot, 'packages/tooling/nx-webpieces-rules/templates/eslint.webpieces.config.mjs');
28
+ const workspacePath = join(workspaceRoot, 'eslint.webpieces.config.mjs');
29
+
30
+ // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
31
+ try {
32
+ const templateContent = readFileSync(templatePath, 'utf-8');
33
+ const workspaceContent = readFileSync(workspacePath, 'utf-8');
34
+
35
+ const templateRules = extractRulesSection(templateContent);
36
+ const workspaceRules = extractRulesSection(workspaceContent);
37
+
38
+ const templateHash = calculateHash(normalizeContent(templateRules));
39
+ const workspaceHash = calculateHash(normalizeContent(workspaceRules));
40
+
41
+ if (templateHash !== workspaceHash) {
42
+ printValidationError(templatePath, workspacePath);
43
+ return { success: false };
44
+ }
45
+
46
+ console.log('āœ… ESLint configuration sync validated - rules match!');
47
+ return { success: true };
48
+
49
+ } catch (err: unknown) {
50
+ // Error occurred during validation - log and fail
51
+ // eslint-disable-next-line @webpieces/catch-error-pattern
52
+ console.error('āŒ Error validating ESLint sync:', err);
53
+ return { success: false };
54
+ }
55
+ }
56
+
57
+ function printValidationError(templatePath: string, workspacePath: string): void {
58
+ console.error('');
59
+ console.error('āŒ ESLint configuration sync validation FAILED');
60
+ console.error('');
61
+ console.error('The @webpieces ESLint rules must be identical in both files:');
62
+ console.error(` 1. ${templatePath}`);
63
+ console.error(` 2. ${workspacePath}`);
64
+ console.error('');
65
+ console.error('These files must have identical rules sections so that:');
66
+ console.error(' - External clients get the same rules we use internally');
67
+ console.error(' - We "eat our own dog food" - same rules for everyone');
68
+ console.error('');
69
+ console.error('To fix:');
70
+ console.error(' 1. Modify the rules in ONE file (recommend: templates/eslint.webpieces.config.mjs)');
71
+ console.error(' 2. Copy the rules section to the other file');
72
+ console.error(' 3. Keep import statements different (template uses npm, workspace uses loadWorkspaceRules)');
73
+ console.error('');
74
+ console.error('Customization for webpieces workspace goes in: eslint.config.mjs');
75
+ console.error('');
76
+ }
77
+
78
+ function extractRulesSection(content: string): string {
79
+ // Extract everything between "export default [" and the final "];"
80
+ // This includes the rules configuration
81
+ const match = content.match(/export default \[([\s\S]*)\];/);
82
+ if (!match) {
83
+ throw new Error('Could not extract rules section - export default not found');
84
+ }
85
+
86
+ return match[1].trim();
87
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "title": "Validate ESLint Sync Executor",
4
+ "description": "Validates that workspace and template eslint.webpieces.config.mjs files have identical rules",
5
+ "type": "object",
6
+ "properties": {}
7
+ }
@@ -0,0 +1,11 @@
1
+ import type { ExecutorContext } from '@nx/devkit';
2
+ import { ExecutorResult } from '../../executor-result';
3
+ import { validateModifiedFiles } from '@webpieces/code-rules';
4
+
5
+ export default async function runExecutor(
6
+ // webpieces-disable no-any-unknown -- options are passed through to code-rules validators
7
+ options: Record<string, unknown>,
8
+ context: ExecutorContext,
9
+ ): Promise<ExecutorResult> {
10
+ return validateModifiedFiles(options, context.root);
11
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "title": "Validate Modified Files Executor",
4
+ "description": "Validates that modified files don't exceed a maximum line count. Encourages keeping files small and focused.",
5
+ "type": "object",
6
+ "properties": {
7
+ "limit": {
8
+ "type": "number",
9
+ "description": "Maximum number of lines allowed for modified files",
10
+ "default": 900
11
+ },
12
+ "mode": {
13
+ "type": "string",
14
+ "enum": ["OFF", "MODIFIED_FILES"],
15
+ "description": "OFF: skip validation. MODIFIED_FILES: validate all code in modified files.",
16
+ "default": "MODIFIED_FILES"
17
+ },
18
+ "disableAllowed": {
19
+ "type": "boolean",
20
+ "description": "Whether disable comments work. When false, no escape hatch (like old STRICT mode).",
21
+ "default": true
22
+ }
23
+ },
24
+ "required": []
25
+ }
@@ -0,0 +1,11 @@
1
+ import type { ExecutorContext } from '@nx/devkit';
2
+ import { ExecutorResult } from '../../executor-result';
3
+ import { validateModifiedMethods } from '@webpieces/code-rules';
4
+
5
+ export default async function runExecutor(
6
+ // webpieces-disable no-any-unknown -- options are passed through to code-rules validators
7
+ options: Record<string, unknown>,
8
+ context: ExecutorContext,
9
+ ): Promise<ExecutorResult> {
10
+ return validateModifiedMethods(options, context.root);
11
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "title": "Validate Modified Methods Executor",
4
+ "description": "Validates that modified methods don't exceed a maximum line count. Encourages gradual cleanup of legacy long methods.",
5
+ "type": "object",
6
+ "properties": {
7
+ "limit": {
8
+ "type": "number",
9
+ "description": "Maximum lines allowed for modified methods",
10
+ "default": 80
11
+ },
12
+ "mode": {
13
+ "type": "string",
14
+ "enum": ["OFF", "NEW_METHODS", "NEW_AND_MODIFIED_METHODS", "MODIFIED_FILES"],
15
+ "description": "OFF: skip validation. NEW_AND_MODIFIED_METHODS: new methods + methods with changes. MODIFIED_FILES: all methods in modified files.",
16
+ "default": "NEW_AND_MODIFIED_METHODS"
17
+ },
18
+ "disableAllowed": {
19
+ "type": "boolean",
20
+ "description": "Whether disable comments work. When false, no escape hatch (like old STRICT mode).",
21
+ "default": true
22
+ }
23
+ },
24
+ "required": []
25
+ }
@@ -0,0 +1,11 @@
1
+ import type { ExecutorContext } from '@nx/devkit';
2
+ import { ExecutorResult } from '../../executor-result';
3
+ import { validateNewMethods } from '@webpieces/code-rules';
4
+
5
+ export default async function runExecutor(
6
+ // webpieces-disable no-any-unknown -- options are passed through to code-rules validators
7
+ options: Record<string, unknown>,
8
+ context: ExecutorContext,
9
+ ): Promise<ExecutorResult> {
10
+ return validateNewMethods(options, context.root);
11
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "title": "Validate New Methods Executor",
4
+ "description": "Validates that newly added methods don't exceed a maximum line count. Only runs in affected mode (when NX_BASE is set).",
5
+ "type": "object",
6
+ "properties": {
7
+ "limit": {
8
+ "type": "number",
9
+ "description": "Maximum lines allowed for new methods",
10
+ "default": 80
11
+ },
12
+ "mode": {
13
+ "type": "string",
14
+ "enum": ["OFF", "NEW_METHODS", "NEW_AND_MODIFIED_METHODS", "MODIFIED_FILES"],
15
+ "description": "OFF: skip validation. NEW_METHODS: only new methods in diff. NEW_AND_MODIFIED_METHODS: new methods + methods with changes. MODIFIED_FILES: all methods in modified files.",
16
+ "default": "NEW_AND_MODIFIED_METHODS"
17
+ },
18
+ "disableAllowed": {
19
+ "type": "boolean",
20
+ "description": "Whether disable comments work. When false, no escape hatch.",
21
+ "default": true
22
+ }
23
+ },
24
+ "required": []
25
+ }
@@ -0,0 +1,11 @@
1
+ import type { ExecutorContext } from '@nx/devkit';
2
+ import { ExecutorResult } from '../../executor-result';
3
+ import { validateNoAnyUnknown } from '@webpieces/code-rules';
4
+
5
+ export default async function runExecutor(
6
+ // webpieces-disable no-any-unknown -- options are passed through to code-rules validators
7
+ options: Record<string, unknown>,
8
+ context: ExecutorContext,
9
+ ): Promise<ExecutorResult> {
10
+ return validateNoAnyUnknown(options, context.root);
11
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "title": "Validate No Any Unknown Executor",
4
+ "description": "Validates that `any` and `unknown` TypeScript keywords are not used. Uses LINE-BASED detection for git diff filtering.",
5
+ "type": "object",
6
+ "properties": {
7
+ "mode": {
8
+ "type": "string",
9
+ "enum": ["OFF", "MODIFIED_CODE", "MODIFIED_FILES"],
10
+ "description": "OFF: skip validation. MODIFIED_CODE: only changed lines in diff. MODIFIED_FILES: all in modified files. Disallows `any` and `unknown` TypeScript keywords.",
11
+ "default": "OFF"
12
+ },
13
+ "disableAllowed": {
14
+ "type": "boolean",
15
+ "description": "Whether disable comments work. When false, no escape hatch.",
16
+ "default": true
17
+ },
18
+ "ignoreModifiedUntilEpoch": {
19
+ "type": "number",
20
+ "description": "Epoch seconds. Until this time, skip validation entirely. When expired, normal mode resumes. Omit when not needed."
21
+ }
22
+ },
23
+ "required": []
24
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Validate No Architecture Cycles Executor
3
+ *
4
+ * Validates that the architecture dependency graph has no circular dependencies.
5
+ * This is a fast check that only validates acyclicity at the project level.
6
+ *
7
+ * Usage:
8
+ * nx run architecture:validate-no-architecture-cycles
9
+ */
10
+
11
+ import type { ExecutorContext } from '@nx/devkit';
12
+ import { generateGraph } from '../../lib/graph-generator';
13
+ import { sortGraphTopologically } from '../../lib/graph-sorter';
14
+ import { toError } from '../../toError';
15
+
16
+ export interface ValidateNoCyclesOptions {
17
+ // No options needed
18
+ }
19
+
20
+ export interface ExecutorResult {
21
+ success: boolean;
22
+ }
23
+
24
+ export default async function runExecutor(
25
+ _options: ValidateNoCyclesOptions,
26
+ _context: ExecutorContext
27
+ ): Promise<ExecutorResult> {
28
+ console.log('\nšŸ”„ Validating No Circular Dependencies\n');
29
+
30
+ // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
31
+ try {
32
+ // Step 1: Generate current graph from project.json files
33
+ console.log('šŸ“Š Generating dependency graph from project.json files...');
34
+ const rawGraph = await generateGraph();
35
+
36
+ // Step 2: Topological sort (validates acyclic)
37
+ console.log('šŸ”„ Checking for cycles (topological sort)...');
38
+ // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
39
+ try {
40
+ sortGraphTopologically(rawGraph);
41
+ console.log('āœ… No circular dependencies detected!');
42
+
43
+ // Print summary
44
+ const projectCount = Object.keys(rawGraph).length;
45
+ console.log(`\nšŸ“ˆ Summary: ${projectCount} projects, all acyclic`);
46
+
47
+ return { success: true };
48
+ } catch (err: unknown) {
49
+ const error = toError(err);
50
+ console.error('āŒ Circular dependency detected!');
51
+ console.error(error.message);
52
+ console.error('\nTo fix:');
53
+ console.error(' 1. Review the cycle above');
54
+ console.error(' 2. Break the cycle by refactoring dependencies');
55
+ console.error(' 3. Run this check again');
56
+ return { success: false };
57
+ }
58
+ } catch (err: unknown) {
59
+ const error = toError(err);
60
+ console.error('āŒ Cycle validation failed:', error.message);
61
+ return { success: false };
62
+ }
63
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "title": "Validate No Cycles Executor",
4
+ "description": "Validates that the architecture graph has no circular dependencies",
5
+ "type": "object",
6
+ "properties": {},
7
+ "required": []
8
+ }